mCRL2
Loading...
Searching...
No Matches
probabilistic_data_expression.h
Go to the documentation of this file.
1// Author(s): Jan Friso Groote
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9
17#ifndef MCRL2_LPS_PROBABILISTIC_DATA_EXPRESSION_H
18#define MCRL2_LPS_PROBABILISTIC_DATA_EXPRESSION_H
19
23#include "mcrl2/data/rewriter.h"
24
25
26namespace mcrl2
27{
28namespace lps
29{
30
31namespace detail
32{
33#ifdef MCRL2_ENABLE_MACHINENUMBERS
34 inline utilities::big_natural_number make_bnn_nat(const data::data_expression& n)
35 {
36 utilities::big_natural_number result;
37 data::data_expression const* n_walker=&n;
39 {
40 result.push_back(atermpp::down_cast<data::machine_number>(data::sort_nat::arg2(*n_walker)).value());
41 n_walker=&data::sort_nat::arg1(*n_walker);
42 }
43 std::size_t v=atermpp::down_cast<data::machine_number>(data::sort_nat::arg(*n_walker)).value();
45 if (v>0)
46 {
47 result.push_back(v);
48 }
49 return result;
50 }
51
52 inline utilities::big_natural_number make_bnn_pos(const data::data_expression& n)
53 {
54 utilities::big_natural_number result;
55 data::data_expression const* n_walker=&n;
57 {
58 result.push_back(atermpp::down_cast<data::machine_number>(data::sort_pos::arg2(*n_walker)).value());
59 n_walker=&data::sort_pos::arg1(*n_walker);
60 }
62 result.push_back(atermpp::down_cast<data::machine_number>(data::sort_pos::arg(*n_walker)).value());
63 return result;
64 }
65
66 inline const data::data_expression make_nat_bnn(const utilities::big_natural_number& b)
67 {
68 std::size_t pos=b.size();
69 if (pos==0)
70 {
71 return data::sort_nat::nat(0);
72 }
73 data::data_expression result;
74 data::data_expression word;
75 pos--;
76 data::make_machine_number(word, b[pos]);
78 while (pos>0)
79 {
80 pos--;
81 data::make_machine_number(word, b[pos]);
82 data::sort_nat::make_concat_digit(result, result, word);
83 }
84 return result;
85 }
86
87 inline const data::data_expression make_pos_bnn(const utilities::big_natural_number& b)
88 {
89 std::size_t pos=b.size();
90 assert(pos>0);
91
92 data::data_expression result;
93 data::data_expression word;
94 pos--;
95 data::make_machine_number(word, b[pos]);
97 while (pos>0)
98 {
99 pos--;
100 data::make_machine_number(word, b[pos]);
101 data::sort_pos::make_concat_digit(result, result, word);
102 }
103 return result;
104 }
105#endif
106
107 // An algorithm to calculate the greatest common divisor
108 inline std::size_t greatest_common_divisor(std::size_t x, std::size_t y)
109 {
110 if (x==0) return y;
111 if (y==0) return x;
112 if (x>y)
113 {
114 const std::size_t temp=x; x=y; y=temp; // swap(x,y)
115 }
116
117 std::size_t remainder=y % x;
118 while (remainder!=0)
119 {
120 y=x;
121 x=remainder;
122 remainder=y % x;
123 }
124 return x;
125 }
126
127 inline void remove_common_divisor(std::size_t& enumerator, std::size_t& denominator)
128 {
129 std::size_t gcd=greatest_common_divisor(enumerator,denominator);
130 enumerator=enumerator/gcd;
131 denominator=denominator/gcd;
132 }
133
134}
135
145{
146
147 protected:
148
150 {
153 return d;
154 }
155
157 {
159 return m_r;
160 }
161
162 inline static std::size_t to_number_t(const std::string& s)
163 {
164 return std::stoul(s);
165 }
166
167#ifdef MCRL2_ENABLE_MACHINENUMBERS
168 probabilistic_data_expression calculate_plus_minus(const data_expression& other, const bool is_minus) const
169 {
170 const data_expression& this_enumerator=data::sort_real::left(*this);
171 const data_expression& this_denominator=data::sort_real::right(*this);
172 const data_expression& other_enumerator=data::sort_real::left(other);
173 const data_expression& other_denominator=data::sort_real::right(other);
174 bool negate_first=false;
175 bool negate_second=is_minus;
176 bool second_is_negative=false;
177 if (data::sort_int::is_cneg_application(this_enumerator))
178 {
179 negate_first=true;
180 }
181 if (data::sort_int::is_cneg_application(other_enumerator))
182 {
183 negate_second=!negate_second;
184 second_is_negative=true;
185 }
186 const data_expression& this_enumerator_arg=data::sort_int::arg(this_enumerator);
187 const data_expression& other_enumerator_arg=data::sort_int::arg(other_enumerator);
192 {
193 std::size_t n_this_enumerator=atermpp::down_cast<data::machine_number>(data::sort_nat::arg(this_enumerator_arg)).value();
194 std::size_t n_other_enumerator=atermpp::down_cast<data::machine_number>(data::sort_nat::arg(other_enumerator_arg)).value();
195 std::size_t n_this_denominator=atermpp::down_cast<data::machine_number>(data::sort_pos::arg(this_denominator)).value();
196 std::size_t n_other_denominator=atermpp::down_cast<data::machine_number>(data::sort_pos::arg(other_denominator)).value();
197 //
198 // Removing the common denominators makes the multiplication slightly smaller, keeping the
199 // numbers hopefully slightly more often in the 64 bit boundary of digits.
200 std::size_t gcd = detail::greatest_common_divisor(n_this_denominator, n_other_denominator);
201 std::size_t n_this_denominator_with_gcd=n_this_denominator;
202 n_this_denominator = n_this_denominator / gcd;
203 n_other_denominator = n_other_denominator / gcd;
204
205 std::size_t left_carry=0;
206 std::size_t right_carry=0;
207 std::size_t denominator_carry=0;
208
209 std::size_t left_result=utilities::detail::multiply_single_number(n_this_enumerator,n_other_denominator, left_carry);
210 std::size_t right_result=utilities::detail::multiply_single_number(n_other_enumerator,n_this_denominator, right_carry);
211 std::size_t new_denominator=utilities::detail::multiply_single_number(n_other_denominator,n_this_denominator_with_gcd, denominator_carry);
212
213 std::size_t new_enumerator_carry=0;
214 std::size_t new_enumerator=0;
215 bool result_is_negative=negate_first;
216 if (negate_first==negate_second)
217 {
218 new_enumerator=utilities::detail::add_single_number(left_result, right_result, new_enumerator_carry);
219 }
220 else if (left_result>=right_result)
221 {
222 new_enumerator=left_result-right_result;
223 }
224 else
225 {
226 new_enumerator=right_result-left_result;
227 result_is_negative=!result_is_negative;
228 }
229 if (left_carry==0 && right_carry==0 && denominator_carry==0 && new_enumerator_carry==0)
230 {
231 // We did obtain a result within 64 digit numbers.
232 utilities::detail::remove_common_divisor(new_enumerator, new_denominator);
233
234 data_expression result1 = data::sort_nat::nat(new_enumerator);
235 const data_expression result2 = data::sort_pos::pos(new_denominator);
236 if (result_is_negative)
237 {
238 data::sort_int::make_cneg(result1,result1);
239 }
240 else
241 {
242 data::sort_int::make_cint(result1,result1);
243 }
244
245 data::sort_real::make_creal(result1, result1, result2);
246 assert(is_minus || m_rewriter()(data::sort_real::plus(*this,other))==result1);
247 assert(!is_minus || m_rewriter()(data::sort_real::minus(*this,other))==result1);
248 return probabilistic_data_expression(result1);
249 }
250 }
251 // In this case one of the components of *this or other has more than one digit, or there are carries when doing the calculation.
252 const utilities::big_natural_number bnn_this_enumerator=
253 negate_first?
254 detail::make_bnn_pos(this_enumerator_arg):
255 detail::make_bnn_nat(this_enumerator_arg);
256 const utilities::big_natural_number bnn_other_enumerator=
257 second_is_negative?
258 detail::make_bnn_pos(other_enumerator_arg):
259 detail::make_bnn_nat(other_enumerator_arg);
260 const utilities::big_natural_number bnn_this_denominator=detail::make_bnn_pos(this_denominator);
261 const utilities::big_natural_number bnn_other_denominator=detail::make_bnn_pos(other_denominator);
262 const utilities::probabilistic_arbitrary_precision_fraction left_arg(bnn_this_enumerator, bnn_this_denominator);
263 const utilities::probabilistic_arbitrary_precision_fraction right_arg(bnn_other_enumerator, bnn_other_denominator);
264 data::data_expression result1, result2;
265 if (negate_first==negate_second)
266 {
267 utilities::probabilistic_arbitrary_precision_fraction result=left_arg+right_arg;
268 result2 = detail::make_pos_bnn(result.denominator());
269 if (negate_first)
270 {
271 result1 = detail::make_pos_bnn(result.enumerator());
272 data::sort_int::make_cneg(result1, result1);
273 }
274 else
275 {
276 result1 = detail::make_nat_bnn(result.enumerator());
277 data::sort_int::make_cint(result1, result1);
278 }
279 }
280 else if (left_arg>right_arg)
281 {
282 utilities::probabilistic_arbitrary_precision_fraction result=left_arg-right_arg;
283 result2 = detail::make_pos_bnn(result.denominator());
284 if (negate_first)
285 {
286 result1 = detail::make_pos_bnn(result.enumerator());
287 data::sort_int::make_cneg(result1, result1);
288 }
289 else
290 {
291 result1 = detail::make_nat_bnn(result.enumerator());
292 data::sort_int::make_cint(result1, result1);
293 }
294 }
295 else
296 {
297 utilities::probabilistic_arbitrary_precision_fraction result=right_arg-left_arg;
298 result2 = detail::make_pos_bnn(result.denominator());
299 if (negate_first)
300 {
301 result1 = detail::make_nat_bnn(result.enumerator());
302 data::sort_int::make_cint(result1, result1);
303 }
304 else
305 {
306 result1 = detail::make_pos_bnn(result.enumerator());
307 data::sort_int::make_cneg(result1, result1);
308 }
309 }
310 data::sort_real::make_creal(result1, result1, result2);
311
312 assert(is_minus || m_rewriter()(data::sort_real::plus(*this,other))==result1);
313 assert(!is_minus || m_rewriter()(data::sort_real::minus(*this,other))==result1);
314 return probabilistic_data_expression(result1);
315 }
316#endif
317
318 public:
321 {
322 using namespace data;
324 return zero;
325 }
326
329 {
330 using namespace data;
332 return one;
333 }
334
335 /* \brief Default constructor.
336 */
338 : data::data_expression(zero())
339 {}
340
344 : data::data_expression(d)
345 {
346 assert(d.sort()==data::sort_real::real_());
347 }
348
349 /* \brief Constructor on the basis of two numbers. The denominator must not be 0.
350 */
351 probabilistic_data_expression(std::size_t enumerator, std::size_t denominator)
352 {
353 assert(denominator!=0);
354 detail::remove_common_divisor(enumerator,denominator);
356 }
357
358 /* \brief A constructor, where the enumerator and denominator are constructed
359 * from two strings of digits.
360 */
361 probabilistic_data_expression(const std::string& enumerator, const std::string& denominator)
362 {
363 assert(enumerator.size() <= denominator.size());
364 const data_expression d_enumerator=data::sort_nat::nat(enumerator);
365 const data_expression d_denominator=data::sort_pos::pos(denominator);
367 }
368
369 /* \brief Standard comparison operator.
370 */
372 {
373#ifdef MCRL2_ENABLE_MACHINENUMBERS
374 if (static_cast<data_expression>(*this)==static_cast<data_expression>(other))
375 {
376 return true;
377 }
378 return false;
379#else
380 const data_expression result= m_rewriter()(data::equal_to(*this,other));
381 if (result==data::sort_bool::true_())
382 {
383 return true;
384 }
385 if (result==data::sort_bool::false_())
386 {
387 return false;
388 }
389 throw mcrl2::runtime_error("Equality between fractions does not rewrite to true or false: " + pp(result) + ".");
390#endif
391 }
392
393 /* \brief Standard comparison operator.
394 */
396 {
397 return !this->operator==(other);
398 }
399
400 /* \brief Standard comparison operator.
401 */
403 {
404#ifdef MCRL2_ENABLE_MACHINENUMBERS
405 const data_expression& this_enumerator=data::sort_real::left(*this);
406 const data_expression& this_denominator=data::sort_real::right(*this);
407 const data_expression& other_enumerator=data::sort_real::left(other);
408 const data_expression& other_denominator=data::sort_real::right(other);
409 bool negate_outcome=false;
410 if (data::sort_int::is_cneg_application(this_enumerator))
411 {
412 if (data::sort_int::is_cneg_application(other_enumerator))
413 {
414 negate_outcome=true;
415 }
416 else
417 {
418 assert(data::sort_int::is_cint_application(other_enumerator));
419assert(data::sort_bool::true_()==m_rewriter()(data::less(*this,other)));
420 return true; // First number is negative, second is positive or zero.
421 }
422 }
423 else
424 {
425 if (data::sort_int::is_cneg_application(other_enumerator))
426 {
427assert(data::sort_bool::false_()==m_rewriter()(data::less(*this,other)));
428 return false; //First number is positive or zero, second is negative.
429 }
430 assert(data::sort_int::is_cint_application(other_enumerator));
431 }
432 const data_expression& this_enumerator_arg=data::sort_int::arg(this_enumerator);
433 const data_expression& other_enumerator_arg=data::sort_int::arg(other_enumerator);
438 {
439 std::size_t n_this_enumerator=atermpp::down_cast<data::machine_number>(data::sort_nat::arg(this_enumerator_arg)).value();
440 std::size_t n_other_enumerator=atermpp::down_cast<data::machine_number>(data::sort_nat::arg(other_enumerator_arg)).value();
441 std::size_t n_this_denominator=atermpp::down_cast<data::machine_number>(data::sort_pos::arg(this_denominator)).value();
442 std::size_t n_other_denominator=atermpp::down_cast<data::machine_number>(data::sort_pos::arg(other_denominator)).value();
443 std::size_t left_carry=0;
444 std::size_t right_carry=0;
445 std::size_t left_result=utilities::detail::multiply_single_number(n_this_enumerator,n_other_denominator, left_carry);
446 std::size_t right_result=utilities::detail::multiply_single_number(n_other_enumerator,n_this_denominator, right_carry);
447 if (left_carry<right_carry ||
448 (left_carry==right_carry && left_result<right_result))
449 {
450 assert(data::sort_bool::true_()==m_rewriter()(data::less(*this,other)));
451 return !negate_outcome;
452 }
453 else
454 {
455 assert(data::sort_bool::false_()==m_rewriter()(data::less(*this,other)));
456 return negate_outcome;
457 }
458 }
459 // In this case one of the components of *this or other has more than one digit.
460 const utilities::big_natural_number bnn_this_enumerator=detail::make_bnn_nat(this_enumerator_arg);
461 const utilities::big_natural_number bnn_other_enumerator=detail::make_bnn_nat(other_enumerator_arg);
462 const utilities::big_natural_number bnn_this_denominator=detail::make_bnn_pos(this_denominator);
463 const utilities::big_natural_number bnn_other_denominator=detail::make_bnn_pos(other_denominator);
464 utilities::big_natural_number bnn_left_result;
465 utilities::big_natural_number bnn_right_result;
467 bnn_this_enumerator.multiply(bnn_other_denominator, bnn_left_result, bnn_buffer);
468 bnn_other_enumerator.multiply(bnn_this_denominator, bnn_right_result, bnn_buffer);
469 if (bnn_left_result<bnn_right_result)
470 {
471 return !negate_outcome;
472 }
473 else
474 {
475 return negate_outcome;
476 }
477#else
478 const data_expression result= m_rewriter()(data::less(*this,other));
479 if (result==data::sort_bool::true_())
480 {
481 return true;
482 }
483 if (result==data::sort_bool::false_())
484 {
485 return false;
486 }
487 throw mcrl2::runtime_error("Comparison of fraction does not rewrite to true or false: " + pp(result) + ".");
488#endif
489 }
490
491 /* \brief Standard comparison operator.
492 */
494 {
495 return !this->operator>(other);
496 }
497
498 /* \brief Standard comparison operator.
499 */
501 {
502 return other.operator<(*this);
503 }
504
505 /* \brief Standard comparison operator.
506 */
508 {
509 return other.operator<=(*this);
510 }
511
516 {
517#ifdef MCRL2_ENABLE_MACHINENUMBERS
518 return calculate_plus_minus(other, false);
519#else
521#endif
522 }
523
524
528 {
529#ifdef MCRL2_ENABLE_MACHINENUMBERS
530 return calculate_plus_minus(other, true);
531#else
533#endif
534 }
535};
536
537/* \brief A pretty print operator on action labels, returning it as a string.
538*/
539inline std::string pp(const probabilistic_data_expression& l)
540{
541 return pp(static_cast<data::data_expression>(l));
542}
543
546inline
547std::ostream& operator<<(std::ostream& out, const probabilistic_data_expression& x)
548{
549 return out << static_cast<data::data_expression>(x);
550}
551
552
553} // namespace lps
554} // namespace mcrl2
555
556namespace std
557{
558
559template <>
560struct hash<mcrl2::lps::probabilistic_data_expression >
561{
563 {
564 hash<atermpp::aterm> aterm_hasher;
565 return aterm_hasher(p);
566 }
567};
568
569} // namespace std
570
571#endif // MCRL2_LPS_PROBABILISTIC_DATA_EXPRESSION_H
572
573
This file contains a class big_natural_number that stores big positive numbers of arbitrary size....
size_type size() const
Returns the number of arguments of this term.
Definition aterm.h:151
data_expression()
\brief Default constructor X3.
sort_expression sort() const
Returns the sort of the data expression.
Definition data.cpp:108
Rewriter that operates on data expressions.
Definition rewriter.h:81
void add_sort(const basic_sort &s)
Adds a sort to this specification.
This class contains labels for probabilistic transistions, consisting of a numerator and a denumerato...
static probabilistic_data_expression one()
Constant one.
probabilistic_data_expression operator+(const probabilistic_data_expression &other) const
Standard addition operator. Note that the expression is not evaluated. For this the rewriter has to b...
probabilistic_data_expression(const data::data_expression &d)
Construct a probabilistic_data_expression from a data_expression, which must be of sort real.
bool operator==(const probabilistic_data_expression &other) const
probabilistic_data_expression(std::size_t enumerator, std::size_t denominator)
bool operator!=(const probabilistic_data_expression &other) const
bool operator>=(const probabilistic_data_expression &other) const
bool operator<(const probabilistic_data_expression &other) const
bool operator<=(const probabilistic_data_expression &other) const
bool operator>(const probabilistic_data_expression &other) const
probabilistic_data_expression(const std::string &enumerator, const std::string &denominator)
static std::size_t to_number_t(const std::string &s)
probabilistic_data_expression operator-(const probabilistic_data_expression &other) const
Standard subtraction operator.
static data::data_specification data_specification_with_real()
static probabilistic_data_expression zero()
Constant zero.
Standard exception class for reporting runtime errors.
Definition exception.h:27
void multiply(const big_natural_number &other, big_natural_number &result, big_natural_number &calculation_buffer_for_multiplicand) const
The class rewriter.
const function_symbol & false_()
Constructor for function symbol false.
Definition bool.h:109
const function_symbol & true_()
Constructor for function symbol true.
Definition bool.h:77
const data_expression & arg(const data_expression &e)
Function for projecting out argument. arg from an application.
Definition int1.h:1492
void make_cneg(data_expression &result, const data_expression &arg0)
Make an application of function symbol @cNeg.
Definition int1.h:176
bool is_cneg_application(const atermpp::aterm &e)
Recogniser for application of @cNeg.
Definition int1.h:186
bool is_cint_application(const atermpp::aterm &e)
Recogniser for application of @cInt.
Definition int1.h:124
const function_symbol & cint()
Constructor for function symbol @cInt.
Definition int1.h:80
void make_cint(data_expression &result, const data_expression &arg0)
Make an application of function symbol @cInt.
Definition int1.h:114
const basic_sort & int_()
Constructor for sort expression Int.
Definition int1.h:47
const basic_sort & nat()
Constructor for sort expression Nat.
Definition nat1.h:46
void make_most_significant_digit_nat(data_expression &result, const data_expression &arg0)
Make an application of function symbol @most_significant_digitNat.
Definition nat64.h:335
const data_expression & arg2(const data_expression &e)
Function for projecting out argument. arg2 from an application.
Definition nat1.h:2233
const data_expression & arg1(const data_expression &e)
Function for projecting out argument. arg1 from an application.
Definition nat1.h:2221
void make_concat_digit(data_expression &result, const data_expression &arg0, const data_expression &arg1)
Make an application of function symbol @concat_digit.
Definition nat64.h:412
bool is_concat_digit_application(const atermpp::aterm &e)
Recogniser for application of @concat_digit.
Definition nat64.h:422
const data_expression & arg(const data_expression &e)
Function for projecting out argument. arg from an application.
Definition nat1.h:2209
bool is_most_significant_digit_nat_application(const atermpp::aterm &e)
Recogniser for application of @most_significant_digitNat.
Definition nat64.h:345
const data_expression & arg(const data_expression &e)
Function for projecting out argument. arg from an application.
Definition pos1.h:788
void make_most_significant_digit(data_expression &result, const data_expression &arg0)
Make an application of function symbol @most_significant_digit.
Definition pos64.h:239
const data_expression & arg1(const data_expression &e)
Function for projecting out argument. arg1 from an application.
Definition pos1.h:800
const data_expression & arg2(const data_expression &e)
Function for projecting out argument. arg2 from an application.
Definition pos1.h:812
bool is_most_significant_digit_application(const atermpp::aterm &e)
Recogniser for application of @most_significant_digit.
Definition pos64.h:249
bool is_concat_digit_application(const atermpp::aterm &e)
Recogniser for application of @concat_digit.
Definition pos64.h:313
const basic_sort & pos()
Constructor for sort expression Pos.
Definition pos1.h:45
void make_concat_digit(data_expression &result, const data_expression &arg0, const data_expression &arg1)
Make an application of function symbol @concat_digit.
Definition pos64.h:303
function_symbol plus(const sort_expression &s0, const sort_expression &s1)
Definition real1.h:1059
const function_symbol & creal()
Constructor for function symbol @cReal.
Definition real1.h:107
data_expression & real_one()
data_expression & real_zero()
NUMERIC_TYPE value(const data_expression &r, typename std::enable_if< std::is_floating_point< NUMERIC_TYPE >::value >::type *=nullptr)
Yields the real value of a data expression.
function_symbol minus(const sort_expression &s0, const sort_expression &s1)
Definition real1.h:1152
const basic_sort & real_()
Constructor for sort expression Real.
Definition real1.h:48
const data_expression & right(const data_expression &e)
Function for projecting out argument. right from an application.
Definition real1.h:1953
const data_expression & left(const data_expression &e)
Function for projecting out argument. left from an application.
Definition real1.h:1941
void make_creal(data_expression &result, const data_expression &arg0, const data_expression &arg1)
Make an application of function symbol @cReal.
Definition real1.h:143
void make_machine_number(atermpp::aterm &t, size_t n)
function_symbol less(const sort_expression &s)
Constructor for function symbol <.
Definition standard.h:240
function_symbol equal_to(const sort_expression &s)
Constructor for function symbol ==.
Definition standard.h:126
void remove_common_divisor(std::size_t &enumerator, std::size_t &denominator)
std::size_t greatest_common_divisor(std::size_t x, std::size_t y)
std::string pp(const action_summand &x)
Definition lps.cpp:26
std::ostream & operator<<(std::ostream &out, const action_summand &x)
void remove_common_divisor(std::size_t &p, std::size_t &q)
std::size_t multiply_single_number(const std::size_t n1, const std::size_t n2, std::size_t &multiplication_carry)
Definition big_numbers.h:95
std::size_t add_single_number(const std::size_t n1, const std::size_t n2, std::size_t &carry)
Definition big_numbers.h:49
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
Definition indexed_set.h:72
STL namespace.
This file contains a class that contains labels for probabilistic transitions. These consist of a 64 ...
Contains a number of auxiliary functions to recognize reals.
std::size_t operator()(const mcrl2::lps::probabilistic_data_expression &p) const
#define hash(l, r, m)
Definition tree_set.cpp:23