Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
BinaryNumericalFunctionExpression.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <cmath>
3#include <optional>
4
11
17
18namespace storm {
19namespace expressions {
21 std::shared_ptr<BaseExpression const> const& firstOperand,
22 std::shared_ptr<BaseExpression const> const& secondOperand, OperatorType operatorType)
23 : BinaryExpression(manager, type, firstOperand, secondOperand), operatorType(operatorType) {
24 // Intentionally left empty.
25}
26
30
64
65template<typename V>
66V logHelper(V const& x, V const& b) {
67 // There is no std::log method for arbitrary bases.
68 // This catches common cases which should yield more accurate results
69 if (b == static_cast<V>(2)) {
70 return std::log2(x);
71 } else if (b == static_cast<V>(10)) {
72 return std::log10(x);
73 } else {
74 return std::log2(x) / std::log2(b);
75 }
76}
77
78int_fast64_t BinaryNumericalFunctionExpression::evaluateAsInt(Valuation const* valuation) const {
79 STORM_LOG_THROW(this->hasIntegerType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as integer.");
80
81 int_fast64_t firstOperandEvaluation = this->getFirstOperand()->evaluateAsInt(valuation);
82 int_fast64_t secondOperandEvaluation = this->getSecondOperand()->evaluateAsInt(valuation);
83 int_fast64_t result = 0;
84 switch (this->getOperatorType()) {
86 result = firstOperandEvaluation + secondOperandEvaluation;
87 break;
89 result = firstOperandEvaluation - secondOperandEvaluation;
90 break;
92 result = firstOperandEvaluation * secondOperandEvaluation;
93 break;
95 result = firstOperandEvaluation / secondOperandEvaluation;
96 break;
98 result = std::min(firstOperandEvaluation, secondOperandEvaluation);
99 break;
101 result = std::max(firstOperandEvaluation, secondOperandEvaluation);
102 break;
104 result = static_cast<int_fast64_t>(std::pow(firstOperandEvaluation, secondOperandEvaluation));
105 break;
107 result = firstOperandEvaluation % secondOperandEvaluation;
108 break;
110 result = logHelper(firstOperandEvaluation, secondOperandEvaluation);
111 break;
112 }
113 return result;
114}
115
117 STORM_LOG_THROW(this->hasNumericalType(), storm::exceptions::InvalidTypeException, "Unable to evaluate expression as double.");
118
119 double firstOperandEvaluation = this->getFirstOperand()->evaluateAsDouble(valuation);
120 double secondOperandEvaluation = this->getSecondOperand()->evaluateAsDouble(valuation);
121 double result = 0;
122 switch (this->getOperatorType()) {
124 result = firstOperandEvaluation + secondOperandEvaluation;
125 break;
127 result = firstOperandEvaluation - secondOperandEvaluation;
128 break;
130 result = firstOperandEvaluation * secondOperandEvaluation;
131 break;
133 result = firstOperandEvaluation / secondOperandEvaluation;
134 break;
136 result = std::min(firstOperandEvaluation, secondOperandEvaluation);
137 break;
139 result = std::max(firstOperandEvaluation, secondOperandEvaluation);
140 break;
142 result = std::pow(firstOperandEvaluation, secondOperandEvaluation);
143 break;
145 result = std::fmod(firstOperandEvaluation, secondOperandEvaluation);
146 break;
148 result = logHelper(firstOperandEvaluation, secondOperandEvaluation);
149 break;
150 }
151 return result;
152}
153
154std::shared_ptr<BaseExpression const> BinaryNumericalFunctionExpression::simplify() const {
155 std::shared_ptr<BaseExpression const> firstOperandSimplified = this->getFirstOperand()->simplify();
156 std::shared_ptr<BaseExpression const> secondOperandSimplified = this->getSecondOperand()->simplify();
157
158 if (firstOperandSimplified->isLiteral() && secondOperandSimplified->isLiteral()) {
159 if (this->hasIntegerType()) {
160 int_fast64_t firstOperandEvaluation = firstOperandSimplified->evaluateAsInt();
161 int_fast64_t secondOperandEvaluation = secondOperandSimplified->evaluateAsInt();
162 std::optional<int_fast64_t> newValue;
163 switch (this->getOperatorType()) {
165 newValue = firstOperandEvaluation + secondOperandEvaluation;
166 break;
168 newValue = firstOperandEvaluation - secondOperandEvaluation;
169 break;
171 newValue = firstOperandEvaluation * secondOperandEvaluation;
172 break;
174 newValue = std::min(firstOperandEvaluation, secondOperandEvaluation);
175 break;
177 newValue = std::max(firstOperandEvaluation, secondOperandEvaluation);
178 break;
180 if (secondOperandEvaluation >= 0) {
181 // Only simplify if this evaluates to an integer.
182 // Otherwise, we note that the type of this expression could change due to simplifications (which might or might not be expected)
183 newValue = static_cast<int_fast64_t>(std::pow(firstOperandEvaluation, secondOperandEvaluation));
184 }
185 break;
187 newValue = firstOperandEvaluation % secondOperandEvaluation;
188 break;
190 // Do not simplify as it is not clear how a non-integer result should be treated.
191 break;
193 if (firstOperandEvaluation % secondOperandEvaluation == 0) {
194 // Only simplify if there is no remainder, because otherwise it is not clear whether we want integer division or floating point
195 // division. Otherwise, we note that the type of this expression could change due to simplifications (which might or might not be
196 // expected)
197 newValue = firstOperandEvaluation / secondOperandEvaluation;
198 }
199 break;
200 }
201 if (newValue) {
202 return std::shared_ptr<BaseExpression>(new IntegerLiteralExpression(this->getManager(), newValue.value()));
203 }
204 } else if (this->hasRationalType()) {
205 storm::RationalNumber firstOperandEvaluation = firstOperandSimplified->evaluateAsRational();
206 storm::RationalNumber secondOperandEvaluation = secondOperandSimplified->evaluateAsRational();
207 std::optional<storm::RationalNumber> newValue;
208 switch (this->getOperatorType()) {
210 newValue = firstOperandEvaluation + secondOperandEvaluation;
211 break;
213 newValue = firstOperandEvaluation - secondOperandEvaluation;
214 break;
216 newValue = firstOperandEvaluation * secondOperandEvaluation;
217 break;
219 newValue = std::min(firstOperandEvaluation, secondOperandEvaluation);
220 break;
222 newValue = std::max(firstOperandEvaluation, secondOperandEvaluation);
223 break;
225 newValue = firstOperandEvaluation / secondOperandEvaluation;
226 break;
227 case OperatorType::Power: {
228 if (carl::isInteger(secondOperandEvaluation)) {
229 auto exponent = carl::toInt<carl::sint>(secondOperandEvaluation);
230 if (exponent >= 0) {
231 newValue = carl::pow(firstOperandEvaluation, exponent);
232 } else {
233 storm::RationalNumber power = carl::pow(firstOperandEvaluation, -exponent);
234 newValue = storm::utility::one<storm::RationalNumber>() / power;
235 }
236 }
237 break;
238 }
240 if (carl::isInteger(firstOperandEvaluation) && carl::isInteger(secondOperandEvaluation)) {
241 newValue = storm::utility::mod(storm::utility::numerator(firstOperandEvaluation), storm::utility::numerator(secondOperandEvaluation));
242 }
243 break;
244 }
246 // Do not simplify as it is not clear how a non-rational result should be treated.
247 break;
248 }
249 if (newValue) {
250 return std::shared_ptr<BaseExpression>(new RationalLiteralExpression(this->getManager(), newValue.value()));
251 }
252 }
253 }
254
255 if (firstOperandSimplified.get() == this->getFirstOperand().get() && secondOperandSimplified.get() == this->getSecondOperand().get()) {
256 return this->shared_from_this();
257 } else {
258 return std::shared_ptr<BaseExpression>(new BinaryNumericalFunctionExpression(this->getManager(), this->getType(), firstOperandSimplified,
259 secondOperandSimplified, this->getOperatorType()));
260 }
261}
262
263boost::any BinaryNumericalFunctionExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const {
264 return visitor.visit(*this, data);
265}
266
270
271void BinaryNumericalFunctionExpression::printToStream(std::ostream& stream) const {
272 stream << "(";
273 switch (this->getOperatorType()) {
275 stream << *this->getFirstOperand() << " + " << *this->getSecondOperand();
276 break;
278 stream << *this->getFirstOperand() << " - " << *this->getSecondOperand();
279 break;
281 stream << *this->getFirstOperand() << " * " << *this->getSecondOperand();
282 break;
284 stream << *this->getFirstOperand() << " / " << *this->getSecondOperand();
285 break;
287 stream << "min(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")";
288 break;
290 stream << "max(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")";
291 break;
293 stream << *this->getFirstOperand() << " ^ " << *this->getSecondOperand();
294 break;
296 stream << *this->getFirstOperand() << " % " << *this->getSecondOperand();
297 break;
299 stream << "log(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")";
300 break;
301 }
302 stream << ")";
303}
304} // namespace expressions
305} // 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)
LabParser.cpp.
Definition cli.cpp:18