user_expression_transform_1.cpp 29 KB

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