Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
BinaryNumericalFunctionExpression.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cmath>
5#include <optional>
6
16
17namespace storm {
18namespace expressions {
20 std::shared_ptr<BaseExpression const> const& firstOperand,
21 std::shared_ptr<BaseExpression const> const& secondOperand, OperatorType operatorType)
22 : BinaryExpression(manager, type, firstOperand, secondOperand), operatorType(operatorType) {
23 // Intentionally left empty.
24}
25
29
63
64template<typename V>
65V logHelper(V const& x, V const& b) {
66 // There is no std::log method for arbitrary bases.
67 // This catches common cases which should yield more accurate results
68 if (b == static_cast<V>(2)) {
69 return std::log2(x);
70 } else if (b == static_cast<V>(10)) {
71 return std::log10(x);
72 } else {
73 return std::log2(x) / std::log2(b);
74 }
75}
76
77int_fast64_t BinaryNumericalFunctionExpression::evaluateAsInt(Valuation const* valuation) const {
78 STORM_LOG_THROW(this->hasIntegerType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as integer.");
79
80 int_fast64_t firstOperandEvaluation = this->getFirstOperand()->evaluateAsInt(valuation);
81 int_fast64_t secondOperandEvaluation = this->getSecondOperand()->evaluateAsInt(valuation);
82 int_fast64_t result = 0;
83 switch (this->getOperatorType()) {
85 result = firstOperandEvaluation + secondOperandEvaluation;
86 break;
88 result = firstOperandEvaluation - secondOperandEvaluation;
89 break;
91 result = firstOperandEvaluation * secondOperandEvaluation;
92 break;
94 result = firstOperandEvaluation / secondOperandEvaluation;
95 break;
97 result = std::min(firstOperandEvaluation, secondOperandEvaluation);
98 break;
100 result = std::max(firstOperandEvaluation, secondOperandEvaluation);
101 break;
103 result = static_cast<int_fast64_t>(std::pow(firstOperandEvaluation, secondOperandEvaluation));
104 break;
106 result = firstOperandEvaluation % secondOperandEvaluation;
107 break;
109 result = logHelper(firstOperandEvaluation, secondOperandEvaluation);
110 break;
111 }
112 return result;
113}
114
116 STORM_LOG_THROW(this->hasNumericalType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as double.");
117
118 double firstOperandEvaluation = this->getFirstOperand()->evaluateAsDouble(valuation);
119 double secondOperandEvaluation = this->getSecondOperand()->evaluateAsDouble(valuation);
120 double result = 0;
121 switch (this->getOperatorType()) {
123 result = firstOperandEvaluation + secondOperandEvaluation;
124 break;
126 result = firstOperandEvaluation - secondOperandEvaluation;
127 break;
129 result = firstOperandEvaluation * secondOperandEvaluation;
130 break;
132 result = firstOperandEvaluation / secondOperandEvaluation;
133 break;
135 result = std::min(firstOperandEvaluation, secondOperandEvaluation);
136 break;
138 result = std::max(firstOperandEvaluation, secondOperandEvaluation);
139 break;
141 result = std::pow(firstOperandEvaluation, secondOperandEvaluation);
142 break;
144 result = std::fmod(firstOperandEvaluation, secondOperandEvaluation);
145 break;
147 result = logHelper(firstOperandEvaluation, secondOperandEvaluation);
148 break;
149 }
150 return result;
151}
152
153std::shared_ptr<BaseExpression const> BinaryNumericalFunctionExpression::simplify() const {
154 std::shared_ptr<BaseExpression const> firstOperandSimplified = this->getFirstOperand()->simplify();
155 std::shared_ptr<BaseExpression const> secondOperandSimplified = this->getSecondOperand()->simplify();
156
157 if (firstOperandSimplified->isLiteral() && secondOperandSimplified->isLiteral()) {
158 if (this->hasIntegerType()) {
159 int_fast64_t firstOperandEvaluation = firstOperandSimplified->evaluateAsInt();
160 int_fast64_t secondOperandEvaluation = secondOperandSimplified->evaluateAsInt();
161 std::optional<int_fast64_t> newValue;
162 switch (this->getOperatorType()) {
164 newValue = firstOperandEvaluation + secondOperandEvaluation;
165 break;
167 newValue = firstOperandEvaluation - secondOperandEvaluation;
168 break;
170 newValue = firstOperandEvaluation * secondOperandEvaluation;
171 break;
173 newValue = std::min(firstOperandEvaluation, secondOperandEvaluation);
174 break;
176 newValue = std::max(firstOperandEvaluation, secondOperandEvaluation);
177 break;
179 if (secondOperandEvaluation >= 0) {
180 // Only simplify if this evaluates to an integer.
181 // Otherwise, we note that the type of this expression could change due to simplifications (which might or might not be expected)
182 newValue = static_cast<int_fast64_t>(std::pow(firstOperandEvaluation, secondOperandEvaluation));
183 }
184 break;
186 newValue = firstOperandEvaluation % secondOperandEvaluation;
187 break;
189 // Do not simplify as it is not clear how a non-integer result should be treated.
190 break;
192 if (firstOperandEvaluation % secondOperandEvaluation == 0) {
193 // Only simplify if there is no remainder, because otherwise it is not clear whether we want integer division or floating point
194 // division. Otherwise, we note that the type of this expression could change due to simplifications (which might or might not be
195 // expected)
196 newValue = firstOperandEvaluation / secondOperandEvaluation;
197 }
198 break;
199 }
200 if (newValue) {
201 return std::shared_ptr<BaseExpression>(new IntegerLiteralExpression(this->getManager(), newValue.value()));
202 }
203 } else if (this->hasRationalType()) {
204 storm::RationalNumber firstOperandEvaluation = firstOperandSimplified->evaluateAsRational();
205 storm::RationalNumber secondOperandEvaluation = secondOperandSimplified->evaluateAsRational();
206 std::optional<storm::RationalNumber> newValue;
207 switch (this->getOperatorType()) {
209 newValue = firstOperandEvaluation + secondOperandEvaluation;
210 break;
212 newValue = firstOperandEvaluation - secondOperandEvaluation;
213 break;
215 newValue = firstOperandEvaluation * secondOperandEvaluation;
216 break;
218 newValue = std::min(firstOperandEvaluation, secondOperandEvaluation);
219 break;
221 newValue = std::max(firstOperandEvaluation, secondOperandEvaluation);
222 break;
224 newValue = firstOperandEvaluation / secondOperandEvaluation;
225 break;
226 case OperatorType::Power: {
227 if (carl::isInteger(secondOperandEvaluation)) {
228 auto exponent = carl::toInt<carl::sint>(secondOperandEvaluation);
229 if (exponent >= 0) {
230 newValue = carl::pow(firstOperandEvaluation, exponent);
231 } else {
232 storm::RationalNumber power = carl::pow(firstOperandEvaluation, -exponent);
233 newValue = storm::utility::one<storm::RationalNumber>() / power;
234 }
235 }
236 break;
237 }
239 if (carl::isInteger(firstOperandEvaluation) && carl::isInteger(secondOperandEvaluation)) {
240 newValue = storm::utility::mod(storm::utility::numerator(firstOperandEvaluation), storm::utility::numerator(secondOperandEvaluation));
241 }
242 break;
243 }
245 // Do not simplify as it is not clear how a non-rational result should be treated.
246 break;
247 }
248 if (newValue) {
249 return std::shared_ptr<BaseExpression>(new RationalLiteralExpression(this->getManager(), newValue.value()));
250 }
251 }
252 }
253
254 if (firstOperandSimplified.get() == this->getFirstOperand().get() && secondOperandSimplified.get() == this->getSecondOperand().get()) {
255 return this->shared_from_this();
256 } else {
257 return std::shared_ptr<BaseExpression>(new BinaryNumericalFunctionExpression(this->getManager(), this->getType(), firstOperandSimplified,
258 secondOperandSimplified, this->getOperatorType()));
259 }
260}
261
262boost::any BinaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
263 return visitor.visit(*this, data);
264}
265
269
270void BinaryNumericalFunctionExpression::printToStream(std::ostream& stream) const {
271 stream << "(";
272 switch (this->getOperatorType()) {
274 stream << *this->getFirstOperand() << " + " << *this->getSecondOperand();
275 break;
277 stream << *this->getFirstOperand() << " - " << *this->getSecondOperand();
278 break;
280 stream << *this->getFirstOperand() << " * " << *this->getSecondOperand();
281 break;
283 stream << *this->getFirstOperand() << " / " << *this->getSecondOperand();
284 break;
286 stream << "min(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")";
287 break;
289 stream << "max(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")";
290 break;
292 stream << *this->getFirstOperand() << " ^ " << *this->getSecondOperand();
293 break;
295 stream << *this->getFirstOperand() << " % " << *this->getSecondOperand();
296 break;
298 stream << "log(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")";
299 break;
300 }
301 stream << ")";
302}
303} // namespace expressions
304} // namespace storm
ExpressionManager const & getManager() const
Retrieves the manager responsible for this expression.
bool hasIntegerType() const
Retrieves whether the expression has an integer type.
bool hasRationalType() const
Retrieves whether the expression has a rational return type.
bool hasNumericalType() const
Retrieves whether the expression has a numerical type, i.e., integer or double.
Type const & getType() const
Retrieves the type of the expression.
The base class of all binary expressions.
std::shared_ptr< BaseExpression const > const & getSecondOperand() const
Retrieves the second operand of the expression.
std::shared_ptr< BaseExpression const > const & getFirstOperand() const
Retrieves the first operand of the expression.
virtual double evaluateAsDouble(Valuation const *valuation=nullptr) const override
Evaluates the expression under the valuation of unknowns (variables and constants) given by the valua...
OperatorType getOperatorType() const
Retrieves the operator associated with the expression.
BinaryNumericalFunctionExpression(ExpressionManager const &manager, Type const &type, std::shared_ptr< BaseExpression const > const &firstOperand, std::shared_ptr< BaseExpression const > const &secondOperand, OperatorType operatorType)
Constructs a binary numerical function expression with the given return type, operands and operator.
virtual boost::any accept(ExpressionVisitor &visitor, boost::any const &data) const override
Accepts the given visitor by calling its visit method.
virtual void printToStream(std::ostream &stream) const override
Prints the expression to the given stream.
virtual storm::expressions::OperatorType getOperator() const override
Retrieves the operator of a function application.
virtual int_fast64_t evaluateAsInt(Valuation const *valuation=nullptr) const override
Evaluates the expression under the valuation of unknowns (variables and constants) given by the valua...
OperatorType
An enum type specifying the different operators applicable.
virtual std::shared_ptr< BaseExpression const > simplify() const override
Simplifies the expression according to some simple rules.
This class is responsible for managing a set of typed variables and all expressions using these varia...
virtual boost::any visit(IfThenElseExpression const &expression, boost::any const &data)=0
The base class of all valuations of variables.
Definition Valuation.h:16
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
V logHelper(V const &x, V const &b)
NumberTraits< RationalType >::IntegerType numerator(RationalType const &number)
IntegerType mod(IntegerType const &first, IntegerType const &second)