1 // Copyright (C) 2016-2018 T. Zachary Laine
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 #include <boost/yap/expression.hpp>
7
8 #include <boost/test/minimal.hpp>
9
10
11 template<typename T>
12 using term = boost::yap::terminal<boost::yap::expression, T>;
13
14 template<typename T>
15 using ref = boost::yap::expression_ref<boost::yap::expression, T>;
16
17 namespace yap = boost::yap;
18 namespace bh = boost::hana;
19
20
21 namespace user {
22
23 struct number
24 {
25 double value;
26
operator +(number lhs,number rhs)27 friend number operator+(number lhs, number rhs)
28 {
29 return number{lhs.value + rhs.value};
30 }
31
operator -(number lhs,number rhs)32 friend number operator-(number lhs, number rhs)
33 {
34 return number{lhs.value - rhs.value};
35 }
36
operator *(number lhs,number rhs)37 friend number operator*(number lhs, number rhs)
38 {
39 return number{lhs.value * rhs.value};
40 }
41
operator -(number n)42 friend number operator-(number n) { return number{-n.value}; }
43
operator <(number lhs,double rhs)44 friend bool operator<(number lhs, double rhs)
45 {
46 return lhs.value < rhs;
47 }
48
operator <(double lhs,number rhs)49 friend bool operator<(double lhs, number rhs)
50 {
51 return lhs < rhs.value;
52 }
53 };
54
naxpy(number a,number x,number y)55 number naxpy(number a, number x, number y)
56 {
57 return number{a.value * x.value + y.value + 10.0};
58 }
59
60 struct empty_xform
61 {};
62
63 struct eval_xform_tag
64 {
operator ()user::eval_xform_tag65 decltype(auto) operator()(
66 yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
67 {
68 return n;
69 }
70 };
71
72 struct eval_xform_expr
73 {
operator ()user::eval_xform_expr74 decltype(auto) operator()(term<user::number> const & expr)
75 {
76 return ::boost::yap::value(expr);
77 }
78 };
79
80 struct eval_xform_both
81 {
operator ()user::eval_xform_both82 decltype(auto) operator()(
83 yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
84 {
85 return n;
86 }
87
operator ()user::eval_xform_both88 decltype(auto) operator()(term<user::number> const & expr)
89 {
90 throw std::logic_error("Oops! Picked the wrong overload!");
91 return ::boost::yap::value(expr);
92 }
93 };
94
95 struct plus_to_minus_xform_tag
96 {
operator ()user::plus_to_minus_xform_tag97 decltype(auto) operator()(
98 yap::expr_tag<yap::expr_kind::plus>,
99 user::number const & lhs,
100 user::number const & rhs)
101 {
102 return yap::make_expression<yap::expr_kind::minus>(
103 term<user::number>{lhs}, term<user::number>{rhs});
104 }
105 };
106
107 struct plus_to_minus_xform_expr
108 {
109 template<typename Expr1, typename Expr2>
operator ()user::plus_to_minus_xform_expr110 decltype(auto) operator()(yap::expression<
111 yap::expr_kind::plus,
112 bh::tuple<Expr1, Expr2>> const & expr)
113 {
114 return yap::make_expression<yap::expr_kind::minus>(
115 ::boost::yap::left(expr), ::boost::yap::right(expr));
116 }
117 };
118
119 struct plus_to_minus_xform_both
120 {
operator ()user::plus_to_minus_xform_both121 decltype(auto) operator()(
122 yap::expr_tag<yap::expr_kind::plus>,
123 user::number const & lhs,
124 user::number const & rhs)
125 {
126 return yap::make_expression<yap::expr_kind::minus>(
127 term<user::number>{lhs}, term<user::number>{rhs});
128 }
129
130 template<typename Expr1, typename Expr2>
operator ()user::plus_to_minus_xform_both131 decltype(auto) operator()(yap::expression<
132 yap::expr_kind::plus,
133 bh::tuple<Expr1, Expr2>> const & expr)
134 {
135 throw std::logic_error("Oops! Picked the wrong overload!");
136 return yap::make_expression<yap::expr_kind::minus>(
137 ::boost::yap::left(expr), ::boost::yap::right(expr));
138 }
139 };
140
141 struct term_nonterm_xform_tag
142 {
operator ()user::term_nonterm_xform_tag143 auto operator()(
144 yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
145 {
146 return yap::make_terminal(n * user::number{2.0});
147 }
148
operator ()user::term_nonterm_xform_tag149 auto operator()(
150 yap::expr_tag<yap::expr_kind::plus>,
151 user::number const & lhs,
152 user::number const & rhs)
153 {
154 return yap::make_expression<yap::expr_kind::minus>(
155 yap::transform(::boost::yap::make_terminal(lhs), *this),
156 yap::transform(::boost::yap::make_terminal(rhs), *this));
157 }
158 };
159
160 struct term_nonterm_xform_expr
161 {
operator ()user::term_nonterm_xform_expr162 decltype(auto) operator()(term<user::number> const & expr)
163 {
164 return yap::make_terminal(
165 ::boost::yap::value(expr) * user::number{2.0});
166 }
167
168 template<typename Expr1, typename Expr2>
operator ()user::term_nonterm_xform_expr169 decltype(auto) operator()(yap::expression<
170 yap::expr_kind::plus,
171 bh::tuple<Expr1, Expr2>> const & expr)
172 {
173 return yap::make_expression<yap::expr_kind::minus>(
174 yap::transform(::boost::yap::left(expr), *this),
175 yap::transform(::boost::yap::right(expr), *this));
176 }
177 };
178
179 struct term_nonterm_xform_both
180 {
operator ()user::term_nonterm_xform_both181 decltype(auto) operator()(
182 yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
183 {
184 return yap::make_terminal(n * user::number{2.0});
185 }
186
operator ()user::term_nonterm_xform_both187 decltype(auto) operator()(term<user::number> const & expr)
188 {
189 return yap::make_terminal(
190 ::boost::yap::value(expr) * user::number{2.0});
191 }
192
operator ()user::term_nonterm_xform_both193 decltype(auto) operator()(
194 yap::expr_tag<yap::expr_kind::plus>,
195 user::number const & lhs,
196 user::number const & rhs)
197 {
198 return yap::make_expression<yap::expr_kind::minus>(
199 yap::transform(::boost::yap::make_terminal(lhs), *this),
200 yap::transform(::boost::yap::make_terminal(rhs), *this));
201 }
202
203 template<typename Expr1, typename Expr2>
operator ()user::term_nonterm_xform_both204 decltype(auto) operator()(yap::expression<
205 yap::expr_kind::plus,
206 bh::tuple<Expr1, Expr2>> const & expr)
207 {
208 return yap::make_expression<yap::expr_kind::minus>(
209 yap::transform(::boost::yap::left(expr), *this),
210 yap::transform(::boost::yap::right(expr), *this));
211 }
212 };
213
214 struct eval_term_nonterm_xform_tag
215 {
operator ()user::eval_term_nonterm_xform_tag216 decltype(auto) operator()(
217 yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
218 {
219 return n * user::number{2.0};
220 }
221
222 template<typename Expr1, typename Expr2>
operator ()user::eval_term_nonterm_xform_tag223 decltype(auto) operator()(
224 yap::expr_tag<yap::expr_kind::plus>,
225 Expr1 const & lhs,
226 Expr2 const & rhs)
227 {
228 return boost::yap::transform(::boost::yap::as_expr(lhs), *this) -
229 boost::yap::transform(::boost::yap::as_expr(rhs), *this);
230 }
231 };
232
233 struct eval_term_nonterm_xform_expr
234 {
operator ()user::eval_term_nonterm_xform_expr235 decltype(auto) operator()(term<user::number> const & expr)
236 {
237 return ::boost::yap::value(expr) * user::number{2.0};
238 }
239
240 template<typename Expr1, typename Expr2>
operator ()user::eval_term_nonterm_xform_expr241 decltype(auto) operator()(yap::expression<
242 yap::expr_kind::plus,
243 bh::tuple<Expr1, Expr2>> const & expr)
244 {
245 return boost::yap::transform(::boost::yap::left(expr), *this) -
246 boost::yap::transform(::boost::yap::right(expr), *this);
247 }
248 };
249
250 struct eval_term_nonterm_xform_both
251 {
operator ()user::eval_term_nonterm_xform_both252 decltype(auto) operator()(
253 yap::expr_tag<yap::expr_kind::terminal>, user::number const & n)
254 {
255 return n * user::number{2.0};
256 }
257
operator ()user::eval_term_nonterm_xform_both258 decltype(auto) operator()(term<user::number> const & expr)
259 {
260 return ::boost::yap::value(expr) * user::number{2.0};
261 }
262
263 template<typename Expr1, typename Expr2>
operator ()user::eval_term_nonterm_xform_both264 decltype(auto) operator()(
265 yap::expr_tag<yap::expr_kind::plus>,
266 Expr1 const & lhs,
267 Expr2 const & rhs)
268 {
269 return boost::yap::transform(::boost::yap::as_expr(lhs), *this) -
270 boost::yap::transform(::boost::yap::as_expr(rhs), *this);
271 }
272
273 template<typename Expr1, typename Expr2>
operator ()user::eval_term_nonterm_xform_both274 decltype(auto) operator()(yap::expression<
275 yap::expr_kind::plus,
276 bh::tuple<Expr1, Expr2>> const & expr)
277 {
278 return boost::yap::transform(::boost::yap::left(expr), *this) -
279 boost::yap::transform(::boost::yap::right(expr), *this);
280 }
281 };
282
283 decltype(auto)
naxpy_eager_nontemplate_xform(yap::expression<yap::expr_kind::plus,bh::tuple<yap::expression<yap::expr_kind::multiplies,bh::tuple<ref<term<user::number> &>,ref<term<user::number> &>>>,ref<term<user::number> &>>> const & expr)284 naxpy_eager_nontemplate_xform(yap::expression<
285 yap::expr_kind::plus,
286 bh::tuple<
287 yap::expression<
288 yap::expr_kind::multiplies,
289 bh::tuple<
290 ref<term<user::number> &>,
291 ref<term<user::number> &>>>,
292 ref<term<user::number> &>>> const & expr)
293 {
294 auto a = evaluate(expr.left().left());
295 auto x = evaluate(expr.left().right());
296 auto y = evaluate(expr.right());
297 return yap::make_terminal(naxpy(a, x, y));
298 }
299
300 decltype(auto)
naxpy_lazy_nontemplate_xform(yap::expression<yap::expr_kind::plus,bh::tuple<yap::expression<yap::expr_kind::multiplies,bh::tuple<ref<term<user::number> &>,ref<term<user::number> &>>>,ref<term<user::number> &>>> const & expr)301 naxpy_lazy_nontemplate_xform(yap::expression<
302 yap::expr_kind::plus,
303 bh::tuple<
304 yap::expression<
305 yap::expr_kind::multiplies,
306 bh::tuple<
307 ref<term<user::number> &>,
308 ref<term<user::number> &>>>,
309 ref<term<user::number> &>>> const & expr)
310 {
311 decltype(auto) a = expr.left().left().value();
312 decltype(auto) x = expr.left().right().value();
313 decltype(auto) y = expr.right().value();
314 return yap::make_terminal(naxpy)(a, x, y);
315 }
316
317 struct naxpy_xform
318 {
319 template<typename Expr1, typename Expr2, typename Expr3>
operator ()user::naxpy_xform320 decltype(auto) operator()(yap::expression<
321 yap::expr_kind::plus,
322 bh::tuple<
323 yap::expression<
324 yap::expr_kind::multiplies,
325 bh::tuple<Expr1, Expr2>>,
326 Expr3>> const & expr)
327 {
328 return yap::make_terminal(naxpy)(
329 transform(expr.left().left(), naxpy_xform{}),
330 transform(expr.left().right(), naxpy_xform{}),
331 transform(expr.right(), naxpy_xform{}));
332 }
333 };
334
335
336 // unary transforms
337
338 struct disable_negate_xform_tag
339 {
340 auto
operator ()user::disable_negate_xform_tag341 operator()(yap::expr_tag<yap::expr_kind::negate>, user::number value)
342 {
343 return yap::make_terminal(std::move(value));
344 }
345
346 template<typename Expr>
347 auto
operator ()user::disable_negate_xform_tag348 operator()(yap::expr_tag<yap::expr_kind::negate>, Expr const & expr)
349 {
350 return expr;
351 }
352 };
353
354 struct disable_negate_xform_expr
355 {
356 template<typename Expr>
operator ()user::disable_negate_xform_expr357 decltype(auto) operator()(
358 yap::expression<yap::expr_kind::negate, bh::tuple<Expr>> const &
359 expr)
360 {
361 return ::boost::yap::value(expr);
362 }
363 };
364
365 struct disable_negate_xform_both
366 {
367 decltype(auto)
operator ()user::disable_negate_xform_both368 operator()(yap::expr_tag<yap::expr_kind::negate>, user::number value)
369 {
370 return yap::make_terminal(std::move(value));
371 }
372
373 template<typename Expr>
374 decltype(auto)
operator ()user::disable_negate_xform_both375 operator()(yap::expr_tag<yap::expr_kind::negate>, Expr const & expr)
376 {
377 return expr;
378 }
379
380 template<typename Expr>
operator ()user::disable_negate_xform_both381 decltype(auto) operator()(
382 yap::expression<yap::expr_kind::negate, bh::tuple<Expr>> const &
383 expr)
384 {
385 throw std::logic_error("Oops! Picked the wrong overload!");
386 return ::boost::yap::value(expr);
387 }
388 };
389
390
391 // ternary transforms
392
393 //[ tag_xform
394 struct ternary_to_else_xform_tag
395 {
396 template<typename Expr>
operator ()user::ternary_to_else_xform_tag397 decltype(auto) operator()(
398 boost::yap::expr_tag<yap::expr_kind::if_else>,
399 Expr const & cond,
400 user::number then,
401 user::number else_)
402 {
403 return boost::yap::make_terminal(std::move(else_));
404 }
405 };
406 //]
407
408 //[ expr_xform
409 struct ternary_to_else_xform_expr
410 {
411 template<typename Cond, typename Then, typename Else>
412 decltype(auto)
operator ()user::ternary_to_else_xform_expr413 operator()(boost::yap::expression<
414 boost::yap::expr_kind::if_else,
415 boost::hana::tuple<Cond, Then, Else>> const & expr)
416 {
417 return ::boost::yap::else_(expr);
418 }
419 };
420 //]
421
422 struct ternary_to_else_xform_both
423 {
424 template<typename Expr>
operator ()user::ternary_to_else_xform_both425 decltype(auto) operator()(
426 yap::expr_tag<yap::expr_kind::if_else>,
427 Expr const & cond,
428 user::number then,
429 user::number else_)
430 {
431 return yap::make_terminal(std::move(else_));
432 }
433
434 template<typename Cond, typename Then, typename Else>
operator ()user::ternary_to_else_xform_both435 decltype(auto) operator()(yap::expression<
436 yap::expr_kind::if_else,
437 bh::tuple<Cond, Then, Else>> const & expr)
438 {
439 throw std::logic_error("Oops! Picked the wrong overload!");
440 return ::boost::yap::else_(expr);
441 }
442 };
443 }
444
double_to_float(term<double> expr)445 auto double_to_float(term<double> expr)
446 {
447 return term<float>{(float)expr.value()};
448 }
449
check_unique_ptrs_equal_7(term<std::unique_ptr<int>> && expr)450 auto check_unique_ptrs_equal_7(term<std::unique_ptr<int>> && expr)
451 {
452 using namespace boost::hana::literals;
453 BOOST_CHECK(*expr.elements[0_c] == 7);
454 return std::move(expr);
455 }
456
test_main(int,char * [])457 int test_main(int, char * [])
458 {
459 {
460 term<user::number> a{{1.0}};
461 term<user::number> x{{42.0}};
462 term<user::number> y{{3.0}};
463
464 {
465 auto expr = a;
466 {
467 user::number result = evaluate(expr);
468 BOOST_CHECK(result.value == 1);
469 }
470
471 {
472 auto transformed_expr = transform(expr, user::empty_xform{});
473 user::number result = evaluate(transformed_expr);
474 BOOST_CHECK(result.value == 1);
475 }
476
477 {
478 auto transformed_expr = transform(expr, user::eval_xform_tag{});
479 BOOST_CHECK(transformed_expr.value == 1);
480 }
481
482 {
483 auto transformed_expr =
484 transform(expr, user::eval_xform_expr{});
485 BOOST_CHECK(transformed_expr.value == 1);
486 }
487
488 {
489 auto transformed_expr =
490 transform(expr, user::eval_xform_both{});
491 BOOST_CHECK(transformed_expr.value == 1);
492 }
493 }
494
495 {
496 auto expr = x + y;
497 {
498 user::number result = evaluate(expr);
499 BOOST_CHECK(result.value == 45);
500 }
501
502 {
503 auto transformed_expr =
504 transform(expr, user::plus_to_minus_xform_tag{});
505 user::number result = evaluate(transformed_expr);
506 BOOST_CHECK(result.value == 39);
507 }
508
509 {
510 auto transformed_expr =
511 transform(expr, user::plus_to_minus_xform_expr{});
512 user::number result = evaluate(transformed_expr);
513 BOOST_CHECK(result.value == 39);
514 }
515
516 {
517 auto transformed_expr =
518 transform(expr, user::plus_to_minus_xform_both{});
519 user::number result = evaluate(transformed_expr);
520 BOOST_CHECK(result.value == 39);
521 }
522 }
523
524 {
525 auto expr = x + user::number{3.0};
526 {
527 user::number result = evaluate(expr);
528 BOOST_CHECK(result.value == 45);
529 }
530
531 {
532 auto transformed_expr =
533 transform(expr, user::term_nonterm_xform_tag{});
534 user::number result = evaluate(transformed_expr);
535 BOOST_CHECK(result.value == 39 * 2);
536 }
537
538 {
539 auto transformed_expr =
540 transform(expr, user::term_nonterm_xform_expr{});
541 user::number result = evaluate(transformed_expr);
542 BOOST_CHECK(result.value == 39 * 2);
543 }
544
545 {
546 auto transformed_expr =
547 transform(expr, user::term_nonterm_xform_both{});
548 user::number result = evaluate(transformed_expr);
549 BOOST_CHECK(result.value == 39 * 2);
550 }
551 }
552
553 {
554 auto expr = x + y;
555 {
556 user::number result = evaluate(expr);
557 BOOST_CHECK(result.value == 45);
558 }
559
560 {
561 auto transformed_expr =
562 transform(expr, user::term_nonterm_xform_tag{});
563 user::number result = evaluate(transformed_expr);
564 BOOST_CHECK(result.value == 39 * 2);
565 }
566
567 {
568 auto transformed_expr =
569 transform(expr, user::term_nonterm_xform_expr{});
570 user::number result = evaluate(transformed_expr);
571 BOOST_CHECK(result.value == 39 * 2);
572 }
573
574 {
575 auto transformed_expr =
576 transform(expr, user::term_nonterm_xform_both{});
577 user::number result = evaluate(transformed_expr);
578 BOOST_CHECK(result.value == 39 * 2);
579 }
580 }
581
582 {
583 auto expr = (x + y) + user::number{1.0};
584 {
585 user::number result = evaluate(expr);
586 BOOST_CHECK(result.value == 46);
587 }
588
589 {
590 // Differs from those below, because it matches terminals, not
591 // expressions.
592 auto transformed_expr =
593 transform(expr, user::term_nonterm_xform_tag{});
594 user::number result = evaluate(transformed_expr);
595 BOOST_CHECK(result.value == 40 * 2);
596 }
597
598 {
599 auto transformed_expr =
600 transform(expr, user::term_nonterm_xform_expr{});
601 user::number result = evaluate(transformed_expr);
602 BOOST_CHECK(result.value == 38 * 2);
603 }
604
605 {
606 auto transformed_expr =
607 transform(expr, user::term_nonterm_xform_both{});
608 user::number result = evaluate(transformed_expr);
609 BOOST_CHECK(result.value == 38 * 2);
610 }
611 }
612
613 {
614 auto expr = x + user::number{3.0};
615 {
616 user::number result = evaluate(expr);
617 BOOST_CHECK(result.value == 45);
618 }
619
620 {
621 user::number result =
622 transform(expr, user::eval_term_nonterm_xform_tag{});
623 BOOST_CHECK(result.value == 39 * 2);
624 }
625
626 {
627 user::number result =
628 transform(expr, user::eval_term_nonterm_xform_expr{});
629 BOOST_CHECK(result.value == 39 * 2);
630 }
631
632 {
633 user::number result =
634 transform(expr, user::eval_term_nonterm_xform_both{});
635 BOOST_CHECK(result.value == 39 * 2);
636 }
637 }
638
639 {
640 auto expr = x + y;
641 {
642 user::number result = evaluate(expr);
643 BOOST_CHECK(result.value == 45);
644 }
645
646 {
647 user::number result =
648 transform(expr, user::eval_term_nonterm_xform_tag{});
649 BOOST_CHECK(result.value == 39 * 2);
650 }
651
652 {
653 user::number result =
654 transform(expr, user::eval_term_nonterm_xform_expr{});
655 BOOST_CHECK(result.value == 39 * 2);
656 }
657
658 {
659 user::number result =
660 transform(expr, user::eval_term_nonterm_xform_both{});
661 BOOST_CHECK(result.value == 39 * 2);
662 }
663 }
664
665 {
666 auto expr = (x + y) + user::number{1.0};
667 {
668 user::number result = evaluate(expr);
669 BOOST_CHECK(result.value == 46);
670 }
671
672 {
673 user::number result =
674 transform(expr, user::eval_term_nonterm_xform_tag{});
675 BOOST_CHECK(result.value == 38 * 2);
676 }
677
678 {
679 user::number result =
680 transform(expr, user::eval_term_nonterm_xform_expr{});
681 BOOST_CHECK(result.value == 38 * 2);
682 }
683
684 {
685 user::number result =
686 transform(expr, user::eval_term_nonterm_xform_both{});
687 BOOST_CHECK(result.value == 38 * 2);
688 }
689 }
690
691 {
692 auto expr = a * x + y;
693 {
694 user::number result = evaluate(expr);
695 BOOST_CHECK(result.value == 45);
696 }
697
698 auto transformed_expr =
699 transform(expr, user::naxpy_eager_nontemplate_xform);
700 {
701 user::number result = evaluate(transformed_expr);
702 BOOST_CHECK(result.value == 55);
703 }
704 }
705
706 {
707 auto expr = a + (a * x + y);
708 {
709 user::number result = evaluate(expr);
710 BOOST_CHECK(result.value == 46);
711 }
712
713 auto transformed_expr =
714 transform(expr, user::naxpy_eager_nontemplate_xform);
715 {
716 user::number result = evaluate(transformed_expr);
717 BOOST_CHECK(result.value == 56);
718 }
719 }
720
721 {
722 auto expr = a * x + y;
723 {
724 user::number result = evaluate(expr);
725 BOOST_CHECK(result.value == 45);
726 }
727
728 auto transformed_expr =
729 transform(expr, user::naxpy_lazy_nontemplate_xform);
730 {
731 user::number result = evaluate(transformed_expr);
732 BOOST_CHECK(result.value == 55);
733 }
734 }
735
736 {
737 auto expr = a + (a * x + y);
738 {
739 user::number result = evaluate(expr);
740 BOOST_CHECK(result.value == 46);
741 }
742
743 auto transformed_expr =
744 transform(expr, user::naxpy_lazy_nontemplate_xform);
745 {
746 user::number result = evaluate(transformed_expr);
747 BOOST_CHECK(result.value == 56);
748 }
749 }
750
751 {
752 auto expr = (a * x + y) * (a * x + y) + (a * x + y);
753 {
754 user::number result = evaluate(expr);
755 BOOST_CHECK(result.value == 45 * 45 + 45);
756 }
757
758 auto transformed_expr = transform(expr, user::naxpy_xform{});
759 {
760 user::number result = evaluate(transformed_expr);
761 BOOST_CHECK(result.value == 55 * 55 + 55 + 10);
762 }
763 }
764 }
765
766 {
767 term<double> unity{1.0};
768 term<std::unique_ptr<int>> i{new int{7}};
769 yap::expression<
770 yap::expr_kind::plus,
771 bh::tuple<ref<term<double> &>, term<std::unique_ptr<int>>>>
772 expr_1 = unity + std::move(i);
773
774 yap::expression<
775 yap::expr_kind::plus,
776 bh::tuple<
777 ref<term<double> &>,
778 yap::expression<
779 yap::expr_kind::plus,
780 bh::tuple<
781 ref<term<double> &>,
782 term<std::unique_ptr<int>>>>>>
783 expr_2 = unity + std::move(expr_1);
784
785 auto transformed_expr = transform(std::move(expr_2), double_to_float);
786
787 transform(std::move(transformed_expr), check_unique_ptrs_equal_7);
788 }
789
790 {
791 term<user::number> a{{1.0}};
792 term<user::number> x{{42.0}};
793 term<user::number> y{{3.0}};
794
795 {
796 auto expr = -x;
797 {
798 user::number result = evaluate(expr);
799 BOOST_CHECK(result.value == -42);
800 }
801
802 {
803 auto transformed_expr =
804 transform(expr, user::disable_negate_xform_tag{});
805 user::number result = evaluate(transformed_expr);
806 BOOST_CHECK(result.value == 42);
807 }
808
809 {
810 auto transformed_expr =
811 transform(expr, user::disable_negate_xform_expr{});
812 user::number result = evaluate(transformed_expr);
813 BOOST_CHECK(result.value == 42);
814 }
815
816 {
817 auto transformed_expr =
818 transform(expr, user::disable_negate_xform_both{});
819 user::number result = evaluate(transformed_expr);
820 BOOST_CHECK(result.value == 42);
821 }
822 }
823
824 {
825 auto expr = a * -x + y;
826 {
827 user::number result = evaluate(expr);
828 BOOST_CHECK(result.value == -39);
829 }
830
831 {
832 auto transformed_expr =
833 transform(expr, user::disable_negate_xform_tag{});
834 user::number result = evaluate(transformed_expr);
835 BOOST_CHECK(result.value == 45);
836 }
837
838 {
839 auto transformed_expr =
840 transform(expr, user::disable_negate_xform_expr{});
841 user::number result = evaluate(transformed_expr);
842 BOOST_CHECK(result.value == 45);
843 }
844
845 {
846 auto transformed_expr =
847 transform(expr, user::disable_negate_xform_both{});
848 user::number result = evaluate(transformed_expr);
849 BOOST_CHECK(result.value == 45);
850 }
851 }
852
853 {
854 auto expr = -(x + y);
855 {
856 user::number result = evaluate(expr);
857 BOOST_CHECK(result.value == -45);
858 }
859
860 {
861 auto transformed_expr =
862 transform(expr, user::disable_negate_xform_tag{});
863 user::number result = evaluate(transformed_expr);
864 BOOST_CHECK(result.value == 45);
865 }
866
867 {
868 auto transformed_expr =
869 transform(expr, user::disable_negate_xform_expr{});
870 user::number result = evaluate(transformed_expr);
871 BOOST_CHECK(result.value == 45);
872 }
873
874 {
875 auto transformed_expr =
876 transform(expr, user::disable_negate_xform_both{});
877 user::number result = evaluate(transformed_expr);
878 BOOST_CHECK(result.value == 45);
879 }
880 }
881 }
882
883 {
884 term<user::number> a{{1.0}};
885 term<user::number> x{{42.0}};
886 term<user::number> y{{3.0}};
887
888 {
889 auto expr = if_else(0 < a, x, y);
890 {
891 user::number result = evaluate(expr);
892 BOOST_CHECK(result.value == 42);
893 }
894
895 {
896 auto transformed_expr =
897 transform(expr, user::ternary_to_else_xform_tag{});
898 user::number result = evaluate(transformed_expr);
899 BOOST_CHECK(result.value == 3);
900 }
901
902 {
903 auto transformed_expr =
904 transform(expr, user::ternary_to_else_xform_expr{});
905 user::number result = evaluate(transformed_expr);
906 BOOST_CHECK(result.value == 3);
907 }
908
909 {
910 auto transformed_expr =
911 transform(expr, user::ternary_to_else_xform_both{});
912 user::number result = evaluate(transformed_expr);
913 BOOST_CHECK(result.value == 3);
914 }
915 }
916
917 {
918 auto expr = y * if_else(0 < a, x, y) + user::number{0.0};
919 {
920 user::number result = evaluate(expr);
921 BOOST_CHECK(result.value == 126);
922 }
923
924 {
925 auto transformed_expr =
926 transform(expr, user::ternary_to_else_xform_tag{});
927 user::number result = evaluate(transformed_expr);
928 BOOST_CHECK(result.value == 9);
929 }
930
931 {
932 auto transformed_expr =
933 transform(expr, user::ternary_to_else_xform_expr{});
934 user::number result = evaluate(transformed_expr);
935 BOOST_CHECK(result.value == 9);
936 }
937
938 {
939 auto transformed_expr =
940 transform(expr, user::ternary_to_else_xform_both{});
941 user::number result = evaluate(transformed_expr);
942 BOOST_CHECK(result.value == 9);
943 }
944 }
945 }
946
947 return 0;
948 }
949