1 /* Copyright 2009-2016 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8   * the GNU Lesser General Public License as published by the Free
9     Software Foundation; either version 3 of the License, or (at your
10     option) any later version.
11 
12 or
13 
14   * the GNU General Public License as published by the Free Software
15     Foundation; either version 3 of the License, or (at your option) any
16     later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library.  If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #include "../src/monomial.hpp"
30 
31 #define BOOST_TEST_MODULE monomial_01_test
32 #include <boost/test/included/unit_test.hpp>
33 
34 #include <boost/mpl/for_each.hpp>
35 #include <boost/mpl/vector.hpp>
36 #include <cstddef>
37 #include <functional>
38 #include <initializer_list>
39 #include <iostream>
40 #include <limits>
41 #include <list>
42 #include <set>
43 #include <sstream>
44 #include <stdexcept>
45 #include <string>
46 #include <type_traits>
47 #include <unordered_map>
48 #include <unordered_set>
49 #include <vector>
50 
51 #include "../src/exceptions.hpp"
52 #include "../src/init.hpp"
53 #include "../src/key_is_convertible.hpp"
54 #include "../src/key_is_multipliable.hpp"
55 #include "../src/kronecker_monomial.hpp"
56 #include "../src/math.hpp"
57 #include "../src/mp_integer.hpp"
58 #include "../src/mp_rational.hpp"
59 #include "../src/pow.hpp"
60 #include "../src/real.hpp"
61 #include "../src/s11n.hpp"
62 #include "../src/symbol.hpp"
63 #include "../src/symbol_set.hpp"
64 #include "../src/term.hpp"
65 #include "../src/type_traits.hpp"
66 
67 using namespace piranha;
68 
69 typedef boost::mpl::vector<signed char, int, integer, rational> expo_types;
70 typedef boost::mpl::vector<std::integral_constant<std::size_t, 0u>, std::integral_constant<std::size_t, 1u>,
71                            std::integral_constant<std::size_t, 5u>, std::integral_constant<std::size_t, 10u>>
72     size_types;
73 
74 // Constructors, assignments and element access.
75 struct constructor_tester {
76     template <typename T>
77     struct runner {
78         template <typename U>
operator ()constructor_tester::runner79         void operator()(const U &)
80         {
81             typedef monomial<T, U> monomial_type;
82             BOOST_CHECK(is_key<monomial_type>::value);
83             monomial_type m0;
84             BOOST_CHECK_NO_THROW(monomial_type tmp = monomial_type());
85             BOOST_CHECK_NO_THROW(monomial_type tmp = monomial_type(monomial_type()));
86             BOOST_CHECK_NO_THROW(monomial_type tmp(m0));
87             // From init list.
88             monomial_type m1{T(0), T(1), T(2), T(3)};
89             BOOST_CHECK_EQUAL(m1.size(), static_cast<decltype(m1.size())>(4));
90             for (typename monomial_type::size_type i = 0; i < m1.size(); ++i) {
91                 BOOST_CHECK_EQUAL(m1[i], T(i));
92                 BOOST_CHECK_NO_THROW(m1[i] = static_cast<T>(T(i) + T(1)));
93                 BOOST_CHECK_EQUAL(m1[i], T(i) + T(1));
94             }
95             monomial_type m1a{0, 1, 2, 3};
96             BOOST_CHECK_EQUAL(m1a.size(), static_cast<decltype(m1a.size())>(4));
97             for (typename monomial_type::size_type i = 0; i < m1a.size(); ++i) {
98                 BOOST_CHECK_EQUAL(m1a[i], T(i));
99                 BOOST_CHECK_NO_THROW(m1a[i] = static_cast<T>(T(i) + T(1)));
100                 BOOST_CHECK_EQUAL(m1a[i], T(i) + T(1));
101             }
102             BOOST_CHECK_NO_THROW(m0 = m1);
103             BOOST_CHECK_NO_THROW(m0 = std::move(m1));
104             // From range and symbol set.
105             std::vector<int> v1;
106             m0 = monomial_type(v1.begin(), v1.end(), symbol_set{});
107             BOOST_CHECK_EQUAL(m0.size(), 0u);
108             v1 = {-1};
109             m0 = monomial_type(v1.begin(), v1.end(), symbol_set{symbol{"x"}});
110             BOOST_CHECK_EQUAL(m0.size(), 1u);
111             BOOST_CHECK_EQUAL(m0[0], -1);
112             v1 = {-1, 2};
113             m0 = monomial_type(v1.begin(), v1.end(), symbol_set{symbol{"x"}, symbol{"y"}});
114             BOOST_CHECK_EQUAL(m0.size(), 2u);
115             BOOST_CHECK_EQUAL(m0[0], -1);
116             BOOST_CHECK_EQUAL(m0[1], 2);
117             BOOST_CHECK_THROW(m0 = monomial_type(v1.begin(), v1.end(), symbol_set{symbol{"x"}}), std::invalid_argument);
118             std::list<int> l1;
119             m0 = monomial_type(l1.begin(), l1.end(), symbol_set{});
120             BOOST_CHECK_EQUAL(m0.size(), 0u);
121             l1 = {-1};
122             m0 = monomial_type(l1.begin(), l1.end(), symbol_set{symbol{"x"}});
123             BOOST_CHECK_EQUAL(m0.size(), 1u);
124             BOOST_CHECK_EQUAL(m0[0], -1);
125             l1 = {-1, 2};
126             m0 = monomial_type(l1.begin(), l1.end(), symbol_set{symbol{"x"}, symbol{"y"}});
127             BOOST_CHECK_EQUAL(m0.size(), 2u);
128             BOOST_CHECK_EQUAL(m0[0], -1);
129             BOOST_CHECK_EQUAL(m0[1], 2);
130             BOOST_CHECK_THROW(m0 = monomial_type(l1.begin(), l1.end(), symbol_set{symbol{"x"}}), std::invalid_argument);
131             struct foo {
132             };
133             BOOST_CHECK((!std::is_constructible<monomial_type, foo *, foo *, symbol_set>::value));
134             BOOST_CHECK((std::is_constructible<monomial_type, int *, int *, symbol_set>::value));
135             // From range and symbol set.
136             v1.clear();
137             m0 = monomial_type(v1.begin(), v1.end());
138             BOOST_CHECK_EQUAL(m0.size(), 0u);
139             v1 = {-1};
140             m0 = monomial_type(v1.begin(), v1.end());
141             BOOST_CHECK_EQUAL(m0.size(), 1u);
142             BOOST_CHECK_EQUAL(m0[0], -1);
143             v1 = {-1, 2};
144             m0 = monomial_type(v1.begin(), v1.end());
145             BOOST_CHECK_EQUAL(m0.size(), 2u);
146             BOOST_CHECK_EQUAL(m0[0], -1);
147             BOOST_CHECK_EQUAL(m0[1], 2);
148             l1.clear();
149             m0 = monomial_type(l1.begin(), l1.end());
150             BOOST_CHECK_EQUAL(m0.size(), 0u);
151             l1 = {-1};
152             m0 = monomial_type(l1.begin(), l1.end());
153             BOOST_CHECK_EQUAL(m0.size(), 1u);
154             BOOST_CHECK_EQUAL(m0[0], -1);
155             l1 = {-1, 2};
156             m0 = monomial_type(l1.begin(), l1.end());
157             BOOST_CHECK_EQUAL(m0.size(), 2u);
158             BOOST_CHECK_EQUAL(m0[0], -1);
159             BOOST_CHECK_EQUAL(m0[1], 2);
160             BOOST_CHECK((!std::is_constructible<monomial_type, foo *, foo *>::value));
161             BOOST_CHECK((std::is_constructible<monomial_type, int *, int *>::value));
162             // Constructor from arguments vector.
163             monomial_type m2 = monomial_type(symbol_set{});
164             BOOST_CHECK_EQUAL(m2.size(), unsigned(0));
165             monomial_type m3 = monomial_type(symbol_set({symbol("a"), symbol("b"), symbol("c")}));
166             BOOST_CHECK_EQUAL(m3.size(), unsigned(3));
167             symbol_set vs({symbol("a"), symbol("b"), symbol("c")});
168             monomial_type k2(vs);
169             BOOST_CHECK_EQUAL(k2.size(), vs.size());
170             BOOST_CHECK_EQUAL(k2[0], T(0));
171             BOOST_CHECK_EQUAL(k2[1], T(0));
172             BOOST_CHECK_EQUAL(k2[2], T(0));
173             // Generic constructor for use in series.
174             BOOST_CHECK_THROW(monomial_type tmp(k2, symbol_set{}), std::invalid_argument);
175             monomial_type k3(k2, vs);
176             BOOST_CHECK_EQUAL(k3.size(), vs.size());
177             BOOST_CHECK_EQUAL(k3[0], T(0));
178             BOOST_CHECK_EQUAL(k3[1], T(0));
179             BOOST_CHECK_EQUAL(k3[2], T(0));
180             monomial_type k4(monomial_type(vs), vs);
181             BOOST_CHECK_EQUAL(k4.size(), vs.size());
182             BOOST_CHECK_EQUAL(k4[0], T(0));
183             BOOST_CHECK_EQUAL(k4[1], T(0));
184             BOOST_CHECK_EQUAL(k4[2], T(0));
185             typedef monomial<int, U> monomial_type2;
186             monomial_type2 k5(vs);
187             BOOST_CHECK_THROW(monomial_type tmp(k5, symbol_set{}), std::invalid_argument);
188             monomial_type k6(k5, vs);
189             BOOST_CHECK_EQUAL(k6.size(), vs.size());
190             BOOST_CHECK_EQUAL(k6[0], T(0));
191             BOOST_CHECK_EQUAL(k6[1], T(0));
192             BOOST_CHECK_EQUAL(k6[2], T(0));
193             monomial_type k7(monomial_type2(vs), vs);
194             BOOST_CHECK_EQUAL(k7.size(), vs.size());
195             BOOST_CHECK_EQUAL(k7[0], T(0));
196             BOOST_CHECK_EQUAL(k7[1], T(0));
197             BOOST_CHECK_EQUAL(k7[2], T(0));
198             // Type trait check.
199             BOOST_CHECK((std::is_constructible<monomial_type, monomial_type>::value));
200             BOOST_CHECK((std::is_constructible<monomial_type, symbol_set>::value));
201             BOOST_CHECK((!std::is_constructible<monomial_type, std::string>::value));
202             BOOST_CHECK((!std::is_constructible<monomial_type, monomial_type, int>::value));
203         }
204     };
205     template <typename T>
operator ()constructor_tester206     void operator()(const T &)
207     {
208         boost::mpl::for_each<size_types>(runner<T>());
209     }
210 };
211 
BOOST_AUTO_TEST_CASE(monomial_constructor_test)212 BOOST_AUTO_TEST_CASE(monomial_constructor_test)
213 {
214     init();
215     boost::mpl::for_each<expo_types>(constructor_tester());
216 }
217 
218 struct hash_tester {
219     template <typename T>
220     struct runner {
221         template <typename U>
operator ()hash_tester::runner222         void operator()(const U &)
223         {
224             typedef monomial<T, U> monomial_type;
225             monomial_type m0;
226             BOOST_CHECK_EQUAL(m0.hash(), std::size_t());
227             BOOST_CHECK_EQUAL(m0.hash(), std::hash<monomial_type>()(m0));
228             monomial_type m1{T(0), T(1), T(2), T(3)};
229             BOOST_CHECK_EQUAL(m1.hash(), std::hash<monomial_type>()(m1));
230         }
231     };
232     template <typename T>
operator ()hash_tester233     void operator()(const T &)
234     {
235         boost::mpl::for_each<size_types>(runner<T>());
236     }
237 };
238 
BOOST_AUTO_TEST_CASE(monomial_hash_test)239 BOOST_AUTO_TEST_CASE(monomial_hash_test)
240 {
241     boost::mpl::for_each<expo_types>(hash_tester());
242 }
243 
244 struct compatibility_tester {
245     template <typename T>
246     struct runner {
247         template <typename U>
operator ()compatibility_tester::runner248         void operator()(const U &)
249         {
250             typedef monomial<T, U> monomial_type;
251             monomial_type m0;
252             BOOST_CHECK(m0.is_compatible(symbol_set{}));
253             symbol_set ss({symbol("foobarize")});
254             monomial_type m1{T(0), T(1)};
255             BOOST_CHECK(!m1.is_compatible(ss));
256             monomial_type m2{T(0)};
257             BOOST_CHECK(m2.is_compatible(ss));
258         }
259     };
260     template <typename T>
operator ()compatibility_tester261     void operator()(const T &)
262     {
263         boost::mpl::for_each<size_types>(runner<T>());
264     }
265 };
266 
BOOST_AUTO_TEST_CASE(monomial_compatibility_test)267 BOOST_AUTO_TEST_CASE(monomial_compatibility_test)
268 {
269     boost::mpl::for_each<expo_types>(compatibility_tester());
270 }
271 
272 struct ignorability_tester {
273     template <typename T>
274     struct runner {
275         template <typename U>
operator ()ignorability_tester::runner276         void operator()(const U &)
277         {
278             typedef monomial<T, U> monomial_type;
279             monomial_type m0;
280             BOOST_CHECK(!m0.is_ignorable(symbol_set{}));
281             monomial_type m1{T(0)};
282             BOOST_CHECK(!m1.is_ignorable(symbol_set({symbol("foobarize")})));
283         }
284     };
285     template <typename T>
operator ()ignorability_tester286     void operator()(const T &)
287     {
288         boost::mpl::for_each<size_types>(runner<T>());
289     }
290 };
291 
BOOST_AUTO_TEST_CASE(monomial_ignorability_test)292 BOOST_AUTO_TEST_CASE(monomial_ignorability_test)
293 {
294     boost::mpl::for_each<expo_types>(ignorability_tester());
295 }
296 
297 struct merge_args_tester {
298     template <typename T>
299     struct runner {
300         template <typename U>
operator ()merge_args_tester::runner301         void operator()(const U &)
302         {
303             typedef monomial<T, U> key_type;
304             symbol_set v1, v2;
305             v2.add("a");
306             key_type k;
307             auto out = k.merge_args(v1, v2);
308             BOOST_CHECK_EQUAL(out.size(), unsigned(1));
309             BOOST_CHECK_EQUAL(out[0], T(0));
310             v2.add(symbol("b"));
311             v2.add(symbol("c"));
312             v2.add(symbol("d"));
313             v1.add(symbol("b"));
314             v1.add(symbol("d"));
315             k.push_back(T(2));
316             k.push_back(T(4));
317             out = k.merge_args(v1, v2);
318             BOOST_CHECK_EQUAL(out.size(), unsigned(4));
319             BOOST_CHECK_EQUAL(out[0], T(0));
320             BOOST_CHECK_EQUAL(out[1], T(2));
321             BOOST_CHECK_EQUAL(out[2], T(0));
322             BOOST_CHECK_EQUAL(out[3], T(4));
323             v2.add(symbol("e"));
324             v2.add(symbol("f"));
325             v2.add(symbol("g"));
326             v2.add(symbol("h"));
327             v1.add(symbol("e"));
328             v1.add(symbol("g"));
329             k.push_back(T(5));
330             k.push_back(T(7));
331             out = k.merge_args(v1, v2);
332             BOOST_CHECK_EQUAL(out.size(), unsigned(8));
333             BOOST_CHECK_EQUAL(out[0], T(0));
334             BOOST_CHECK_EQUAL(out[1], T(2));
335             BOOST_CHECK_EQUAL(out[2], T(0));
336             BOOST_CHECK_EQUAL(out[3], T(4));
337             BOOST_CHECK_EQUAL(out[4], T(5));
338             BOOST_CHECK_EQUAL(out[5], T(0));
339             BOOST_CHECK_EQUAL(out[6], T(7));
340             BOOST_CHECK_EQUAL(out[7], T(0));
341         }
342     };
343     template <typename T>
operator ()merge_args_tester344     void operator()(const T &)
345     {
346         boost::mpl::for_each<size_types>(runner<T>());
347     }
348 };
349 
BOOST_AUTO_TEST_CASE(monomial_merge_args_test)350 BOOST_AUTO_TEST_CASE(monomial_merge_args_test)
351 {
352     boost::mpl::for_each<expo_types>(merge_args_tester());
353 }
354 
355 struct is_unitary_tester {
356     template <typename T>
357     struct runner {
358         template <typename U>
operator ()is_unitary_tester::runner359         void operator()(const U &)
360         {
361             typedef monomial<T, U> key_type;
362             symbol_set v1, v2;
363             v2.add(symbol("a"));
364             key_type k(v1);
365             BOOST_CHECK(k.is_unitary(v1));
366             key_type k2(v2);
367             BOOST_CHECK(k2.is_unitary(v2));
368             k2[0] = 1;
369             BOOST_CHECK(!k2.is_unitary(v2));
370             k2[0] = 0;
371             BOOST_CHECK(k2.is_unitary(v2));
372             BOOST_CHECK_THROW(k2.is_unitary(symbol_set{}), std::invalid_argument);
373         }
374     };
375     template <typename T>
operator ()is_unitary_tester376     void operator()(const T &)
377     {
378         boost::mpl::for_each<size_types>(runner<T>());
379     }
380 };
381 
BOOST_AUTO_TEST_CASE(monomial_is_unitary_test)382 BOOST_AUTO_TEST_CASE(monomial_is_unitary_test)
383 {
384     boost::mpl::for_each<expo_types>(is_unitary_tester());
385 }
386 
387 struct degree_tester {
388     template <typename T>
389     struct runner {
390         template <typename U>
operator ()degree_tester::runner391         void operator()(const U &)
392         {
393             typedef monomial<T, U> key_type;
394             key_type k0;
395             symbol_set v;
396             // Check the promotion of short signed ints.
397             if (std::is_same<T, signed char>::value || std::is_same<T, short>::value) {
398                 BOOST_CHECK((std::is_same<int, decltype(k0.degree(v))>::value));
399             } else if (std::is_integral<T>::value) {
400                 BOOST_CHECK((std::is_same<T, decltype(k0.degree(v))>::value));
401             }
402             BOOST_CHECK(key_has_degree<key_type>::value);
403             BOOST_CHECK(key_has_ldegree<key_type>::value);
404             BOOST_CHECK_EQUAL(k0.degree(v), T(0));
405             BOOST_CHECK_EQUAL(k0.ldegree(v), T(0));
406             v.add(symbol("a"));
407             key_type k1(v);
408             BOOST_CHECK_EQUAL(k1.degree(v), T(0));
409             BOOST_CHECK_EQUAL(k1.ldegree(v), T(0));
410             k1[0] = T(2);
411             BOOST_CHECK_EQUAL(k1.degree(v), T(2));
412             BOOST_CHECK_EQUAL(k1.ldegree(v), T(2));
413             v.add(symbol("b"));
414             key_type k2(v);
415             BOOST_CHECK_EQUAL(k2.degree(v), T(0));
416             BOOST_CHECK_EQUAL(k2.ldegree(v), T(0));
417             k2[0] = T(2);
418             k2[1] = T(3);
419             BOOST_CHECK_EQUAL(k2.degree(v), T(2) + T(3));
420             BOOST_CHECK_THROW(k2.degree(symbol_set{}), std::invalid_argument);
421             // Partial degree.
422             using positions = symbol_set::positions;
423             auto ss_to_pos = [](const symbol_set &vs, const std::set<std::string> &s) {
424                 symbol_set tmp;
425                 for (const auto &str : s) {
426                     tmp.add(str);
427                 }
428                 return positions(vs, tmp);
429             };
430             if (std::is_same<T, signed char>::value || std::is_same<T, short>::value) {
431                 BOOST_CHECK((std::is_same<int, decltype(k2.degree(ss_to_pos(v, std::set<std::string>{}), v))>::value));
432             } else if (std::is_integral<T>::value) {
433                 BOOST_CHECK((std::is_same<T, decltype(k2.degree(ss_to_pos(v, std::set<std::string>{}), v))>::value));
434             }
435             BOOST_CHECK(k2.degree(ss_to_pos(v, std::set<std::string>{}), v) == T(0));
436             BOOST_CHECK(k2.degree(ss_to_pos(v, {"a"}), v) == T(2));
437             BOOST_CHECK(k2.degree(ss_to_pos(v, {"A"}), v) == T(0));
438             BOOST_CHECK(k2.degree(ss_to_pos(v, {"z"}), v) == T(0));
439             BOOST_CHECK(k2.degree(ss_to_pos(v, {"z", "A", "a"}), v) == T(2));
440             BOOST_CHECK(k2.degree(ss_to_pos(v, {"z", "A", "b"}), v) == T(3));
441             BOOST_CHECK(k2.degree(ss_to_pos(v, {"B", "A", "b"}), v) == T(3));
442             BOOST_CHECK(k2.degree(ss_to_pos(v, {"a", "b", "z"}), v) == T(3) + T(2));
443             BOOST_CHECK(k2.degree(ss_to_pos(v, {"a", "b", "A"}), v) == T(3) + T(2));
444             BOOST_CHECK(k2.degree(ss_to_pos(v, {"a", "b", "A", "z"}), v) == T(3) + T(2));
445             BOOST_CHECK(k2.ldegree(ss_to_pos(v, std::set<std::string>{}), v) == T(0));
446             BOOST_CHECK(k2.ldegree(ss_to_pos(v, {"a"}), v) == T(2));
447             BOOST_CHECK(k2.ldegree(ss_to_pos(v, {"A"}), v) == T(0));
448             BOOST_CHECK(k2.ldegree(ss_to_pos(v, {"z"}), v) == T(0));
449             BOOST_CHECK(k2.ldegree(ss_to_pos(v, {"z", "A", "a"}), v) == T(2));
450             BOOST_CHECK(k2.ldegree(ss_to_pos(v, {"z", "A", "b"}), v) == T(3));
451             BOOST_CHECK(k2.ldegree(ss_to_pos(v, {"B", "A", "b"}), v) == T(3));
452             BOOST_CHECK(k2.ldegree(ss_to_pos(v, {"a", "b", "z"}), v) == T(3) + T(2));
453             BOOST_CHECK(k2.ldegree(ss_to_pos(v, {"a", "b", "A"}), v) == T(3) + T(2));
454             BOOST_CHECK(k2.ldegree(ss_to_pos(v, {"a", "b", "A", "z"}), v) == T(3) + T(2));
455             v.add(symbol("c"));
456             key_type k3(v);
457             k3[0] = T(2);
458             k3[1] = T(3);
459             k3[2] = T(4);
460             BOOST_CHECK(k3.degree(ss_to_pos(v, {"a", "b", "A", "z"}), v) == T(3) + T(2));
461             BOOST_CHECK(k3.degree(ss_to_pos(v, {"a", "c", "A", "z"}), v) == T(4) + T(2));
462             BOOST_CHECK(k3.degree(ss_to_pos(v, {"a", "c", "b", "z"}), v) == T(4) + T(2) + T(3));
463             BOOST_CHECK(k3.degree(ss_to_pos(v, {"a", "c", "b", "A"}), v) == T(4) + T(2) + T(3));
464             BOOST_CHECK(k3.degree(ss_to_pos(v, {"c", "b", "A"}), v) == T(4) + T(3));
465             BOOST_CHECK(k3.degree(ss_to_pos(v, {"A", "B", "C"}), v) == T(0));
466             BOOST_CHECK(k3.degree(ss_to_pos(v, {"x", "y", "z"}), v) == T(0));
467             BOOST_CHECK(k3.degree(ss_to_pos(v, {"x", "y", "z", "A", "B", "C", "a"}), v) == T(2));
468             // Try partials with bogus positions.
469             symbol_set v2({symbol("a"), symbol("b"), symbol("c"), symbol("d")});
470             BOOST_CHECK_THROW(k3.degree(ss_to_pos(v2, {"d"}), v), std::invalid_argument);
471             BOOST_CHECK_THROW(k3.ldegree(ss_to_pos(v2, {"d"}), v), std::invalid_argument);
472             // Wrong symbol set, will not throw because positions are empty.
473             BOOST_CHECK_EQUAL(k3.degree(ss_to_pos(v2, {"e"}), v), 0);
474         }
475     };
476     template <typename T>
operator ()degree_tester477     void operator()(const T &)
478     {
479         boost::mpl::for_each<size_types>(runner<T>());
480     }
481 };
482 
BOOST_AUTO_TEST_CASE(monomial_degree_test)483 BOOST_AUTO_TEST_CASE(monomial_degree_test)
484 {
485     boost::mpl::for_each<expo_types>(degree_tester());
486     // Test the overflowing.
487     using k_type = monomial<int>;
488     k_type m{std::numeric_limits<int>::max(), 1};
489     symbol_set vs{symbol{"x"}, symbol{"y"}};
490     BOOST_CHECK_THROW(m.degree(vs), std::overflow_error);
491     m = k_type{std::numeric_limits<int>::min(), -1};
492     BOOST_CHECK_THROW(m.degree(vs), std::overflow_error);
493     m = k_type{std::numeric_limits<int>::min(), 1};
494     BOOST_CHECK_EQUAL(m.degree(vs), std::numeric_limits<int>::min() + 1);
495     // Also for partial degree.
496     vs = symbol_set{symbol{"x"}, symbol{"y"}, symbol{"z"}};
497     m = k_type{std::numeric_limits<int>::max(), 1, 0};
498     BOOST_CHECK_EQUAL(m.degree(symbol_set::positions(vs, symbol_set{symbol{"x"}, symbol{"z"}}), vs),
499                       std::numeric_limits<int>::max());
500     BOOST_CHECK_THROW(m.degree(symbol_set::positions(vs, symbol_set{symbol{"x"}, symbol{"y"}}), vs),
501                       std::overflow_error);
502     m = k_type{std::numeric_limits<int>::min(), 0, -1};
503     BOOST_CHECK_EQUAL(m.degree(symbol_set::positions(vs, symbol_set{symbol{"x"}, symbol{"y"}}), vs),
504                       std::numeric_limits<int>::min());
505     BOOST_CHECK_THROW(m.degree(symbol_set::positions(vs, symbol_set{symbol{"x"}, symbol{"z"}}), vs),
506                       std::overflow_error);
507 }
508 
509 // Mock cf with wrong specialisation of mul3.
510 struct mock_cf3 {
511     mock_cf3();
512     explicit mock_cf3(const int &);
513     mock_cf3(const mock_cf3 &);
514     mock_cf3(mock_cf3 &&) noexcept;
515     mock_cf3 &operator=(const mock_cf3 &);
516     mock_cf3 &operator=(mock_cf3 &&) noexcept;
517     friend std::ostream &operator<<(std::ostream &, const mock_cf3 &);
518     mock_cf3 operator-() const;
519     bool operator==(const mock_cf3 &) const;
520     bool operator!=(const mock_cf3 &) const;
521     mock_cf3 &operator+=(const mock_cf3 &);
522     mock_cf3 &operator-=(const mock_cf3 &);
523     mock_cf3 operator+(const mock_cf3 &) const;
524     mock_cf3 operator-(const mock_cf3 &) const;
525     mock_cf3 &operator*=(const mock_cf3 &);
526     mock_cf3 operator*(const mock_cf3 &)const;
527 };
528 
529 namespace piranha
530 {
531 namespace math
532 {
533 
534 template <typename T>
535 struct mul3_impl<T, typename std::enable_if<std::is_same<T, mock_cf3>::value>::type> {
536 };
537 }
538 }
539 
540 struct multiply_tester {
541     template <typename T>
542     struct runner {
543         template <typename U>
operator ()multiply_tester::runner544         void operator()(const U &)
545         {
546             {
547                 // Integer coefficient.
548                 using key_type = monomial<T, U>;
549                 using term_type = term<integer, key_type>;
550                 symbol_set ed;
551                 ed.add("x");
552                 term_type t1, t2;
553                 t1.m_cf = 2;
554                 t1.m_key = key_type{T(2)};
555                 t2.m_cf = 3;
556                 t2.m_key = key_type{T(3)};
557                 std::array<term_type, 1u> res;
558                 key_type::multiply(res, t1, t2, ed);
559                 BOOST_CHECK_EQUAL(res[0].m_cf, t1.m_cf * t2.m_cf);
560                 BOOST_CHECK_EQUAL(res[0].m_key[0], T(5));
561             }
562             {
563                 // Try with rational as well, check special handling.
564                 using key_type = monomial<T, U>;
565                 using term_type = term<rational, key_type>;
566                 symbol_set ed;
567                 ed.add("x");
568                 ed.add("y");
569                 term_type t1, t2;
570                 t1.m_cf = 2 / 3_q;
571                 t1.m_key = key_type{T(2), T(-1)};
572                 t2.m_cf = -3;
573                 t2.m_key = key_type{T(3), T(7)};
574                 std::array<term_type, 1u> res;
575                 key_type::multiply(res, t1, t2, ed);
576                 BOOST_CHECK_EQUAL(res[0].m_cf, -6);
577                 BOOST_CHECK_EQUAL(res[0].m_key[0], T(5));
578                 BOOST_CHECK_EQUAL(res[0].m_key[1], T(6));
579             }
580             // Check throwing as well.
581             using key_type = monomial<T, U>;
582             using term_type = term<rational, key_type>;
583             symbol_set ed;
584             ed.add("x");
585             term_type t1, t2;
586             t1.m_cf = 2 / 3_q;
587             t1.m_key = key_type{T(2), T(-1)};
588             t2.m_cf = -3;
589             t2.m_key = key_type{T(3), T(7)};
590             std::array<term_type, 1u> res;
591             BOOST_CHECK_THROW(key_type::multiply(res, t1, t2, ed), std::invalid_argument);
592             // Check the type trait.
593             BOOST_CHECK((key_is_multipliable<rational, key_type>::value));
594             BOOST_CHECK((key_is_multipliable<integer, key_type>::value));
595             BOOST_CHECK((key_is_multipliable<double, key_type>::value));
596             BOOST_CHECK((!key_is_multipliable<mock_cf3, key_type>::value));
597         }
598     };
599     template <typename T>
operator ()multiply_tester600     void operator()(const T &)
601     {
602         boost::mpl::for_each<size_types>(runner<T>());
603     }
604 };
605 
BOOST_AUTO_TEST_CASE(monomial_multiply_test)606 BOOST_AUTO_TEST_CASE(monomial_multiply_test)
607 {
608     boost::mpl::for_each<expo_types>(multiply_tester());
609 }
610 
611 struct monomial_multiply_tester {
612     template <typename T>
613     struct runner {
614         template <typename U>
operator ()monomial_multiply_tester::runner615         void operator()(const U &)
616         {
617             using key_type = monomial<T, U>;
618             symbol_set ed;
619             key_type k1, k2, res;
620             key_type::multiply(res, k1, k2, ed);
621             BOOST_CHECK(res.size() == 0u);
622             ed.add("x");
623             k1 = key_type{T(2)};
624             k2 = key_type{T(3)};
625             key_type::multiply(res, k1, k2, ed);
626             BOOST_CHECK(res == key_type{T(5)});
627             ed.add("y");
628             BOOST_CHECK_THROW(key_type::multiply(res, k1, k2, ed), std::invalid_argument);
629             BOOST_CHECK(res == key_type{T(5)});
630         }
631     };
632     template <typename T>
operator ()monomial_multiply_tester633     void operator()(const T &)
634     {
635         boost::mpl::for_each<size_types>(runner<T>());
636     }
637 };
638 
BOOST_AUTO_TEST_CASE(monomial_monomial_multiply_test)639 BOOST_AUTO_TEST_CASE(monomial_monomial_multiply_test)
640 {
641     boost::mpl::for_each<expo_types>(monomial_multiply_tester());
642 }
643 
644 struct monomial_divide_tester {
645     template <typename T>
646     struct runner {
647         template <typename U>
operator ()monomial_divide_tester::runner648         void operator()(const U &)
649         {
650             using key_type = monomial<T, U>;
651             symbol_set ed;
652             key_type k1, k2, res;
653             key_type::divide(res, k1, k2, ed);
654             BOOST_CHECK(res.size() == 0u);
655             ed.add("x");
656             k1 = key_type{T(2)};
657             k2 = key_type{T(3)};
658             key_type::divide(res, k1, k2, ed);
659             BOOST_CHECK(res == key_type{T(-1)});
660             ed.add("y");
661             BOOST_CHECK_THROW(key_type::divide(res, k1, k2, ed), std::invalid_argument);
662             BOOST_CHECK(res == key_type{T(-1)});
663         }
664     };
665     template <typename T>
operator ()monomial_divide_tester666     void operator()(const T &)
667     {
668         boost::mpl::for_each<size_types>(runner<T>());
669     }
670 };
671 
BOOST_AUTO_TEST_CASE(monomial_monomial_divide_test)672 BOOST_AUTO_TEST_CASE(monomial_monomial_divide_test)
673 {
674     boost::mpl::for_each<expo_types>(monomial_divide_tester());
675 }
676 
677 struct print_tester {
678     template <typename T>
679     struct runner {
680         template <typename U>
operator ()print_tester::runner681         void operator()(const U &)
682         {
683             typedef monomial<T, U> k_type;
684             symbol_set vs;
685             k_type k1;
686             std::ostringstream oss;
687             k1.print(oss, vs);
688             BOOST_CHECK(oss.str().empty());
689             vs.add("x");
690             k_type k2(vs);
691             k2.print(oss, vs);
692             BOOST_CHECK(oss.str() == "");
693             oss.str("");
694             k_type k3({T(-1)});
695             k3.print(oss, vs);
696             BOOST_CHECK_EQUAL(oss.str(), "x**-1");
697             k_type k4({T(1)});
698             oss.str("");
699             k4.print(oss, vs);
700             BOOST_CHECK(oss.str() == "x");
701             k_type k5({T(-1), T(1)});
702             vs.add("y");
703             oss.str("");
704             k5.print(oss, vs);
705             BOOST_CHECK(oss.str() == "x**-1*y");
706             k_type k6({T(-1), T(-2)});
707             oss.str("");
708             k6.print(oss, vs);
709             BOOST_CHECK(oss.str() == "x**-1*y**-2");
710             k_type k7;
711             BOOST_CHECK_THROW(k7.print(oss, vs), std::invalid_argument);
712         }
713     };
714     template <typename T>
operator ()print_tester715     void operator()(const T &)
716     {
717         boost::mpl::for_each<size_types>(runner<T>());
718     }
719 };
720 
BOOST_AUTO_TEST_CASE(monomial_print_test)721 BOOST_AUTO_TEST_CASE(monomial_print_test)
722 {
723     boost::mpl::for_each<expo_types>(print_tester());
724 }
725 
726 struct linear_argument_tester {
727     template <typename T>
728     struct runner {
729         template <typename U>
operator ()linear_argument_tester::runner730         void operator()(const U &)
731         {
732             typedef monomial<T, U> k_type;
733             symbol_set vs;
734             BOOST_CHECK_THROW(k_type().linear_argument(vs), std::invalid_argument);
735             vs.add("x");
736             BOOST_CHECK_THROW(k_type().linear_argument(vs), std::invalid_argument);
737             k_type k({T(1)});
738             BOOST_CHECK_EQUAL(k.linear_argument(vs), "x");
739             k = k_type({T(0), T(1)});
740             vs.add("y");
741             BOOST_CHECK_EQUAL(k.linear_argument(vs), "y");
742             k = k_type({T(0), T(2)});
743             BOOST_CHECK_THROW(k.linear_argument(vs), std::invalid_argument);
744             k = k_type({T(2), T(0)});
745             BOOST_CHECK_THROW(k.linear_argument(vs), std::invalid_argument);
746             k = k_type({T(1), T(1)});
747             BOOST_CHECK_THROW(k.linear_argument(vs), std::invalid_argument);
748         }
749     };
750     template <typename T>
operator ()linear_argument_tester751     void operator()(const T &)
752     {
753         boost::mpl::for_each<size_types>(runner<T>());
754     }
755 };
756 
BOOST_AUTO_TEST_CASE(monomial_linear_argument_test)757 BOOST_AUTO_TEST_CASE(monomial_linear_argument_test)
758 {
759     boost::mpl::for_each<expo_types>(linear_argument_tester());
760     typedef monomial<rational> k_type;
761     symbol_set vs;
762     vs.add("x");
763     k_type k({rational(1, 2)});
764     BOOST_CHECK_THROW(k.linear_argument(vs), std::invalid_argument);
765     k = k_type({rational(1), rational(0)});
766     vs.add("y");
767     BOOST_CHECK_EQUAL(k.linear_argument(vs), "x");
768     k = k_type({rational(2), rational(1)});
769     BOOST_CHECK_THROW(k.linear_argument(vs), std::invalid_argument);
770 }
771 
772 struct pow_tester {
773     template <typename T>
774     struct runner {
775         template <typename U>
operator ()pow_tester::runner776         void operator()(const U &)
777         {
778             typedef monomial<T, U> k_type;
779             symbol_set vs;
780             k_type k1;
781             BOOST_CHECK(k1 == k1.pow(42, vs));
782             vs.add("x");
783             BOOST_CHECK_THROW(k1.pow(42, vs), std::invalid_argument);
784             k1 = k_type({T(1), T(2), T(3)});
785             vs.add("y");
786             vs.add("z");
787             BOOST_CHECK(k1.pow(2, vs) == k_type({T(2), T(4), T(6)}));
788             BOOST_CHECK(k1.pow(-2, vs) == k_type({T(-2), T(-4), T(-6)}));
789             BOOST_CHECK(k1.pow(0, vs) == k_type({T(0), T(0), T(0)}));
790             vs.add("a");
791             BOOST_CHECK_THROW(k1.pow(42, vs), std::invalid_argument);
792             T tmp;
793             check_overflow(k1, tmp);
794         }
795     };
796     template <typename KType, typename U, typename std::enable_if<std::is_integral<U>::value, int>::type = 0>
check_overflowpow_tester797     static void check_overflow(const KType &, const U &)
798     {
799         KType k2({2});
800         symbol_set vs2;
801         vs2.add("x");
802         BOOST_CHECK_THROW(k2.pow(std::numeric_limits<U>::max(), vs2), std::invalid_argument);
803     }
804     template <typename KType, typename U, typename std::enable_if<!std::is_integral<U>::value, int>::type = 0>
check_overflowpow_tester805     static void check_overflow(const KType &, const U &)
806     {
807     }
808     template <typename T>
operator ()pow_tester809     void operator()(const T &)
810     {
811         boost::mpl::for_each<size_types>(runner<T>());
812     }
813 };
814 
BOOST_AUTO_TEST_CASE(monomial_pow_test)815 BOOST_AUTO_TEST_CASE(monomial_pow_test)
816 {
817     boost::mpl::for_each<expo_types>(pow_tester());
818 }
819 
820 struct fake_int {
821     fake_int();
822     explicit fake_int(int);
823     fake_int(const fake_int &);
824     fake_int(fake_int &&) noexcept;
825     fake_int &operator=(const fake_int &);
826     fake_int &operator=(fake_int &&) noexcept;
827     ~fake_int();
828     bool operator==(const fake_int &) const;
829     bool operator!=(const fake_int &) const;
830     bool operator<(const fake_int &) const;
831     fake_int operator+(const fake_int &) const;
832     fake_int &operator+=(const fake_int &);
833     // Disable the subtraction operators.
834     // fake_int operator-(const fake_int &) const;
835     // fake_int &operator-=(const fake_int &);
836     friend std::ostream &operator<<(std::ostream &, const fake_int &);
837 };
838 
839 struct fake_int_01 {
840     fake_int_01();
841     explicit fake_int_01(int);
842     fake_int_01(const fake_int_01 &);
843     fake_int_01(fake_int_01 &&) noexcept;
844     fake_int_01 &operator=(const fake_int_01 &);
845     fake_int_01 &operator=(fake_int_01 &&) noexcept;
846     ~fake_int_01();
847     bool operator==(const fake_int_01 &) const;
848     bool operator!=(const fake_int_01 &) const;
849     bool operator<(const fake_int_01 &) const;
850     fake_int_01 operator+(const fake_int_01 &) const;
851     fake_int_01 &operator+=(const fake_int_01 &);
852     fake_int_01 operator-(const fake_int_01 &) const;
853     fake_int_01 &operator-=(const fake_int_01 &);
854     friend std::ostream &operator<<(std::ostream &, const fake_int_01 &);
855 };
856 
857 namespace piranha
858 {
859 
860 namespace math
861 {
862 
863 template <>
864 struct negate_impl<fake_int> {
865     void operator()(fake_int &) const;
866 };
867 
868 template <>
869 struct negate_impl<fake_int_01> {
870     void operator()(fake_int_01 &) const;
871 };
872 }
873 }
874 
875 namespace std
876 {
877 
878 template <>
879 struct hash<fake_int> {
880     typedef size_t result_type;
881     typedef fake_int argument_type;
882     result_type operator()(const argument_type &) const;
883 };
884 
885 template <>
886 struct hash<fake_int_01> {
887     typedef size_t result_type;
888     typedef fake_int_01 argument_type;
889     result_type operator()(const argument_type &) const;
890 };
891 }
892 
893 struct partial_tester {
894     template <typename T>
895     struct runner {
896         template <typename U>
operator ()partial_tester::runner897         void operator()(const U &)
898         {
899             typedef monomial<T, U> k_type;
900             BOOST_CHECK(key_is_differentiable<k_type>::value);
901             using positions = symbol_set::positions;
902             auto s_to_pos = [](const symbol_set &v, const symbol &s) {
903                 symbol_set tmp{s};
904                 return positions(v, tmp);
905             };
906             symbol_set vs;
907             k_type k1;
908             vs.add("x");
909             BOOST_CHECK_THROW(k1.partial(s_to_pos(vs, symbol("x")), vs), std::invalid_argument);
910             k1 = k_type({T(2)});
911             auto ret = k1.partial(s_to_pos(vs, symbol("x")), vs);
912             BOOST_CHECK_EQUAL(ret.first, T(2));
913             BOOST_CHECK(ret.second == k_type({T(1)}));
914             // Derivative wrt a variable not in the monomial.
915             ret = k1.partial(s_to_pos(vs, symbol("y")), vs);
916             BOOST_CHECK_EQUAL(ret.first, T(0));
917             BOOST_CHECK(ret.second == k_type{vs});
918             // Derivative wrt a variable which has zero exponent.
919             k1 = k_type({T(0)});
920             ret = k1.partial(s_to_pos(vs, symbol("x")), vs);
921             BOOST_CHECK_EQUAL(ret.first, T(0));
922             BOOST_CHECK(ret.second == k_type{vs});
923             vs.add("y");
924             k1 = k_type({T(-1), T(0)});
925             ret = k1.partial(s_to_pos(vs, symbol("y")), vs);
926             // y has zero exponent.
927             BOOST_CHECK_EQUAL(ret.first, T(0));
928             BOOST_CHECK(ret.second == k_type{vs});
929             ret = k1.partial(s_to_pos(vs, symbol("x")), vs);
930             BOOST_CHECK_EQUAL(ret.first, T(-1));
931             BOOST_CHECK(ret.second == k_type({T(-2), T(0)}));
932             // Check with bogus positions.
933             symbol_set vs2;
934             vs2.add("x");
935             vs2.add("y");
936             vs2.add("z");
937             // The z variable is in position 2, which is outside the size of the monomial.
938             BOOST_CHECK_THROW(k1.partial(s_to_pos(vs2, symbol("z")), vs), std::invalid_argument);
939             // Derivative wrt multiple variables.
940             BOOST_CHECK_THROW(k1.partial(symbol_set::positions(vs2, symbol_set({symbol("x"), symbol("y")})), vs),
941                               std::invalid_argument);
942             // Check the overflow check.
943             overflow_check(k1);
944         }
945         template <typename T2, typename U2, typename std::enable_if<std::is_integral<T2>::value, int>::type = 0>
overflow_checkpartial_tester::runner946         static void overflow_check(const monomial<T2, U2> &)
947         {
948             using positions = symbol_set::positions;
949             auto s_to_pos = [](const symbol_set &v, const symbol &s) {
950                 symbol_set tmp{s};
951                 return positions(v, tmp);
952             };
953             monomial<T2, U2> k({std::numeric_limits<T2>::min()});
954             symbol_set vs;
955             vs.add("x");
956             BOOST_CHECK_THROW(k.partial(s_to_pos(vs, symbol("x")), vs), std::invalid_argument);
957         }
958         template <typename T2, typename U2, typename std::enable_if<!std::is_integral<T2>::value, int>::type = 0>
overflow_checkpartial_tester::runner959         static void overflow_check(const monomial<T2, U2> &)
960         {
961         }
962     };
963     template <typename T>
operator ()partial_tester964     void operator()(const T &)
965     {
966         boost::mpl::for_each<size_types>(runner<T>());
967         // fake_int has no subtraction operators.
968         BOOST_CHECK((!key_is_differentiable<monomial<fake_int>>::value));
969         BOOST_CHECK((key_is_differentiable<monomial<fake_int_01>>::value));
970     }
971 };
972 
BOOST_AUTO_TEST_CASE(monomial_partial_test)973 BOOST_AUTO_TEST_CASE(monomial_partial_test)
974 {
975     boost::mpl::for_each<expo_types>(partial_tester());
976 }
977 
978 struct evaluate_tester {
979     template <typename T>
980     struct runner {
981         template <typename U>
operator ()evaluate_tester::runner982         void operator()(const U &)
983         {
984             using k_type = monomial<T, U>;
985             using pmap_type1 = symbol_set::positions_map<integer>;
986             using dict_type1 = std::unordered_map<symbol, integer>;
987             BOOST_CHECK((key_is_evaluable<k_type, integer>::value));
988             symbol_set vs;
989             k_type k1;
990             BOOST_CHECK_EQUAL(k1.evaluate(pmap_type1(vs, dict_type1{}), vs), integer(1));
991             vs.add("x");
992             // Mismatch between the size of k1 and vs.
993             BOOST_CHECK_THROW(k1.evaluate(pmap_type1(vs, dict_type1{}), vs), std::invalid_argument);
994             k1 = k_type({T(1)});
995             // Empty pmap, k1 has non-zero size.
996             BOOST_CHECK_THROW(k1.evaluate(pmap_type1(vs, dict_type1{}), vs), std::invalid_argument);
997             BOOST_CHECK_EQUAL(k1.evaluate(pmap_type1(vs, dict_type1{{symbol("x"), integer(1)}}), vs), 1);
998             // pmap with invalid position, 1, where the monomial has only 1 element.
999             BOOST_CHECK_THROW(
1000                 k1.evaluate(pmap_type1(symbol_set{symbol{"a"}, symbol{"b"}}, dict_type1{{symbol{"b"}, integer(4)}}),
1001                             vs),
1002                 std::invalid_argument);
1003             k1 = k_type({T(2)});
1004             BOOST_CHECK_EQUAL(k1.evaluate(pmap_type1(vs, dict_type1{{symbol("x"), integer(3)}}), vs), 9);
1005             BOOST_CHECK_EQUAL(
1006                 k1.evaluate(pmap_type1(vs, dict_type1{{symbol("x"), integer(3)}, {symbol("y"), integer(4)}}), vs), 9);
1007             k1 = k_type({T(2), T(4)});
1008             vs.add("y");
1009             BOOST_CHECK_EQUAL(
1010                 k1.evaluate(pmap_type1(vs, dict_type1{{symbol("x"), integer(3)}, {symbol("y"), integer(4)}}), vs),
1011                 2304);
1012             BOOST_CHECK_EQUAL(
1013                 k1.evaluate(pmap_type1(vs, dict_type1{{symbol("y"), integer(4)}, {symbol("x"), integer(3)}}), vs),
1014                 2304);
1015             // pmap has correctly 2 elements, but they refer to indices 0 and 2.
1016             BOOST_CHECK_THROW(k1.evaluate(pmap_type1(symbol_set{symbol{"a"}, symbol{"b"}, symbol{"c"}},
1017                                                      dict_type1{{symbol{"a"}, integer(4)}, {symbol{"c"}, integer(4)}}),
1018                                           vs),
1019                               std::invalid_argument);
1020             // Same with indices 1 and 2.
1021             BOOST_CHECK_THROW(k1.evaluate(pmap_type1(symbol_set{symbol{"a"}, symbol{"b"}, symbol{"c"}},
1022                                                      dict_type1{{symbol{"b"}, integer(4)}, {symbol{"c"}, integer(4)}}),
1023                                           vs),
1024                               std::invalid_argument);
1025             using pmap_type2 = symbol_set::positions_map<double>;
1026             using dict_type2 = std::unordered_map<symbol, double>;
1027             BOOST_CHECK_EQUAL(k1.evaluate(pmap_type2(vs, dict_type2{{symbol("y"), -4.3}, {symbol("x"), 3.2}}), vs),
1028                               math::pow(3.2, 2) * math::pow(-4.3, 4));
1029             using pmap_type3 = symbol_set::positions_map<rational>;
1030             using dict_type3 = std::unordered_map<symbol, rational>;
1031             BOOST_CHECK_EQUAL(
1032                 k1.evaluate(pmap_type3(vs, dict_type3{{symbol("y"), rational(1, 2)}, {symbol("x"), rational(-4, 3)}}),
1033                             vs),
1034                 math::pow(rational(4, -3), 2) * math::pow(rational(-1, -2), 4));
1035             k1 = k_type({T(-2), T(-4)});
1036             BOOST_CHECK_EQUAL(
1037                 k1.evaluate(pmap_type3(vs, dict_type3{{symbol("y"), rational(1, 2)}, {symbol("x"), rational(-4, 3)}}),
1038                             vs),
1039                 math::pow(rational(4, -3), -2) * math::pow(rational(-1, -2), -4));
1040             using pmap_type4 = symbol_set::positions_map<real>;
1041             using dict_type4 = std::unordered_map<symbol, real>;
1042             BOOST_CHECK_EQUAL(
1043                 k1.evaluate(pmap_type4(vs, dict_type4{{symbol("y"), real(1.234)}, {symbol("x"), real(5.678)}}), vs),
1044                 math::pow(real(5.678), -2) * math::pow(real(1.234), -4));
1045         }
1046     };
1047     template <typename T>
operator ()evaluate_tester1048     void operator()(const T &)
1049     {
1050         boost::mpl::for_each<size_types>(runner<T>());
1051     }
1052 };
1053 
BOOST_AUTO_TEST_CASE(monomial_evaluate_test)1054 BOOST_AUTO_TEST_CASE(monomial_evaluate_test)
1055 {
1056     boost::mpl::for_each<expo_types>(evaluate_tester());
1057     BOOST_CHECK((key_is_evaluable<monomial<rational>, double>::value));
1058     BOOST_CHECK((key_is_evaluable<monomial<rational>, real>::value));
1059     BOOST_CHECK((!key_is_evaluable<monomial<rational>, std::string>::value));
1060     BOOST_CHECK((!key_is_evaluable<monomial<rational>, void *>::value));
1061 }
1062 
1063 struct subs_tester {
1064     template <typename T>
1065     struct runner {
1066         template <typename U>
operator ()subs_tester::runner1067         void operator()(const U &)
1068         {
1069             typedef monomial<T, U> k_type;
1070             symbol_set vs;
1071             k_type k1;
1072             // Test the type trait.
1073             BOOST_CHECK((key_has_subs<k_type, integer>::value));
1074             BOOST_CHECK((key_has_subs<k_type, rational>::value));
1075             BOOST_CHECK((key_has_subs<k_type, real>::value));
1076             BOOST_CHECK((key_has_subs<k_type, double>::value));
1077             BOOST_CHECK((!key_has_subs<k_type, std::string>::value));
1078             BOOST_CHECK((!key_has_subs<k_type, std::vector<std::string>>::value));
1079             auto ret = k1.subs("x", integer(4), vs);
1080             BOOST_CHECK_EQUAL(ret.size(), 1u);
1081             BOOST_CHECK_EQUAL(ret[0u].first, 1);
1082             BOOST_CHECK((std::is_same<integer, decltype(ret[0u].first)>::value));
1083             BOOST_CHECK(ret[0u].second == k1);
1084             vs.add("x");
1085             BOOST_CHECK_THROW(k1.subs("x", integer(4), vs), std::invalid_argument);
1086             k1 = k_type({T(2)});
1087             ret = k1.subs("y", integer(4), vs);
1088             BOOST_CHECK_EQUAL(ret.size(), 1u);
1089             BOOST_CHECK_EQUAL(ret[0u].first, 1);
1090             BOOST_CHECK(ret[0u].second == k1);
1091             ret = k1.subs("x", integer(4), vs);
1092             BOOST_CHECK_EQUAL(ret.size(), 1u);
1093             BOOST_CHECK_EQUAL(ret[0u].first, math::pow(integer(4), T(2)));
1094             BOOST_CHECK(ret[0u].second == k_type({T(0)}));
1095             k1 = k_type({T(2), T(3)});
1096             BOOST_CHECK_THROW(k1.subs("x", integer(4), vs), std::invalid_argument);
1097             vs.add("y");
1098             ret = k1.subs("y", integer(-2), vs);
1099             BOOST_CHECK_EQUAL(ret.size(), 1u);
1100             BOOST_CHECK_EQUAL(ret[0u].first, math::pow(integer(-2), T(3)));
1101             BOOST_CHECK((ret[0u].second == k_type{T(2), T(0)}));
1102             auto ret2 = k1.subs("x", real(-2.345), vs);
1103             BOOST_CHECK_EQUAL(ret2.size(), 1u);
1104             BOOST_CHECK_EQUAL(ret2[0u].first, math::pow(real(-2.345), T(2)));
1105             BOOST_CHECK((ret2[0u].second == k_type{T(0), T(3)}));
1106             BOOST_CHECK((std::is_same<real, decltype(ret2[0u].first)>::value));
1107             auto ret3 = k1.subs("x", rational(-1, 2), vs);
1108             BOOST_CHECK_EQUAL(ret3.size(), 1u);
1109             BOOST_CHECK_EQUAL(ret3[0u].first, rational(1, 4));
1110             BOOST_CHECK((ret3[0u].second == k_type{T(0), T(3)}));
1111             BOOST_CHECK((std::is_same<rational, decltype(ret3[0u].first)>::value));
1112         }
1113     };
1114     template <typename T>
operator ()subs_tester1115     void operator()(const T &)
1116     {
1117         boost::mpl::for_each<size_types>(runner<T>());
1118     }
1119 };
1120 
BOOST_AUTO_TEST_CASE(monomial_subs_test)1121 BOOST_AUTO_TEST_CASE(monomial_subs_test)
1122 {
1123     boost::mpl::for_each<expo_types>(subs_tester());
1124 }
1125 
1126 struct print_tex_tester {
1127     template <typename T>
1128     struct runner {
1129         template <typename U>
operator ()print_tex_tester::runner1130         void operator()(const U &)
1131         {
1132             typedef monomial<T, U> k_type;
1133             symbol_set vs;
1134             k_type k1;
1135             std::ostringstream oss;
1136             k1.print_tex(oss, vs);
1137             BOOST_CHECK(oss.str().empty());
1138             k1 = k_type({T(0)});
1139             BOOST_CHECK_THROW(k1.print_tex(oss, vs), std::invalid_argument);
1140             vs.add("x");
1141             k1.print_tex(oss, vs);
1142             BOOST_CHECK_EQUAL(oss.str(), "");
1143             k1 = k_type({T(1)});
1144             k1.print_tex(oss, vs);
1145             BOOST_CHECK_EQUAL(oss.str(), "{x}");
1146             oss.str("");
1147             k1 = k_type({T(-1)});
1148             k1.print_tex(oss, vs);
1149             BOOST_CHECK_EQUAL(oss.str(), "\\frac{1}{{x}}");
1150             oss.str("");
1151             k1 = k_type({T(2)});
1152             k1.print_tex(oss, vs);
1153             BOOST_CHECK_EQUAL(oss.str(), "{x}^{2}");
1154             oss.str("");
1155             k1 = k_type({T(-2)});
1156             k1.print_tex(oss, vs);
1157             BOOST_CHECK_EQUAL(oss.str(), "\\frac{1}{{x}^{2}}");
1158             vs.add("y");
1159             oss.str("");
1160             k1 = k_type({T(-2), T(1)});
1161             k1.print_tex(oss, vs);
1162             BOOST_CHECK_EQUAL(oss.str(), "\\frac{{y}}{{x}^{2}}");
1163             oss.str("");
1164             k1 = k_type({T(-2), T(3)});
1165             k1.print_tex(oss, vs);
1166             BOOST_CHECK_EQUAL(oss.str(), "\\frac{{y}^{3}}{{x}^{2}}");
1167             oss.str("");
1168             k1 = k_type({T(-2), T(-3)});
1169             k1.print_tex(oss, vs);
1170             BOOST_CHECK_EQUAL(oss.str(), "\\frac{1}{{x}^{2}{y}^{3}}");
1171             oss.str("");
1172             k1 = k_type({T(2), T(3)});
1173             k1.print_tex(oss, vs);
1174             BOOST_CHECK_EQUAL(oss.str(), "{x}^{2}{y}^{3}");
1175             oss.str("");
1176             k1 = k_type({T(1), T(3)});
1177             k1.print_tex(oss, vs);
1178             BOOST_CHECK_EQUAL(oss.str(), "{x}{y}^{3}");
1179             oss.str("");
1180             k1 = k_type({T(0), T(3)});
1181             k1.print_tex(oss, vs);
1182             BOOST_CHECK_EQUAL(oss.str(), "{y}^{3}");
1183             oss.str("");
1184             k1 = k_type({T(0), T(0)});
1185             k1.print_tex(oss, vs);
1186             BOOST_CHECK_EQUAL(oss.str(), "");
1187             oss.str("");
1188             k1 = k_type({T(0), T(1)});
1189             k1.print_tex(oss, vs);
1190             BOOST_CHECK_EQUAL(oss.str(), "{y}");
1191             oss.str("");
1192             k1 = k_type({T(0), T(-1)});
1193             k1.print_tex(oss, vs);
1194             BOOST_CHECK_EQUAL(oss.str(), "\\frac{1}{{y}}");
1195         }
1196     };
1197     template <typename T>
operator ()print_tex_tester1198     void operator()(const T &)
1199     {
1200         boost::mpl::for_each<size_types>(runner<T>());
1201     }
1202 };
1203 
BOOST_AUTO_TEST_CASE(monomial_print_tex_test)1204 BOOST_AUTO_TEST_CASE(monomial_print_tex_test)
1205 {
1206     boost::mpl::for_each<expo_types>(print_tex_tester());
1207 }
1208 
1209 struct integrate_tester {
1210     template <typename T>
1211     struct runner {
1212         template <typename U>
operator ()integrate_tester::runner1213         void operator()(const U &)
1214         {
1215             typedef monomial<T, U> k_type;
1216             BOOST_CHECK(key_is_integrable<k_type>::value);
1217             symbol_set vs;
1218             k_type k1;
1219             auto ret = k1.integrate(symbol("a"), vs);
1220             BOOST_CHECK_EQUAL(ret.first, T(1));
1221             BOOST_CHECK(ret.second == k_type({T(1)}));
1222             vs.add("b");
1223             BOOST_CHECK_THROW(k1.integrate(symbol("b"), vs), std::invalid_argument);
1224             k1 = k_type{T(1)};
1225             ret = k1.integrate(symbol("b"), vs);
1226             BOOST_CHECK_EQUAL(ret.first, T(2));
1227             BOOST_CHECK(ret.second == k_type({T(2)}));
1228             k1 = k_type{T(2)};
1229             ret = k1.integrate(symbol("c"), vs);
1230             BOOST_CHECK_EQUAL(ret.first, T(1));
1231             BOOST_CHECK(ret.second == k_type({T(2), T(1)}));
1232             ret = k1.integrate(symbol("a"), vs);
1233             BOOST_CHECK_EQUAL(ret.first, T(1));
1234             BOOST_CHECK(ret.second == k_type({T(1), T(2)}));
1235             k1 = k_type{T(2), T(3)};
1236             vs.add("d");
1237             ret = k1.integrate(symbol("a"), vs);
1238             BOOST_CHECK_EQUAL(ret.first, T(1));
1239             BOOST_CHECK(ret.second == k_type({T(1), T(2), T(3)}));
1240             ret = k1.integrate(symbol("b"), vs);
1241             BOOST_CHECK_EQUAL(ret.first, T(3));
1242             BOOST_CHECK(ret.second == k_type({T(3), T(3)}));
1243             ret = k1.integrate(symbol("c"), vs);
1244             BOOST_CHECK_EQUAL(ret.first, T(1));
1245             BOOST_CHECK(ret.second == k_type({T(2), T(1), T(3)}));
1246             ret = k1.integrate(symbol("d"), vs);
1247             BOOST_CHECK_EQUAL(ret.first, T(4));
1248             BOOST_CHECK(ret.second == k_type({T(2), T(4)}));
1249             ret = k1.integrate(symbol("e"), vs);
1250             BOOST_CHECK_EQUAL(ret.first, T(1));
1251             BOOST_CHECK(ret.second == k_type({T(2), T(3), T(1)}));
1252             k1 = k_type{T(-1), T(3)};
1253             BOOST_CHECK_THROW(k1.integrate(symbol("b"), vs), std::invalid_argument);
1254             k1 = k_type{T(2), T(-1)};
1255             BOOST_CHECK_THROW(k1.integrate(symbol("d"), vs), std::invalid_argument);
1256             // Overflow check.
1257             overflow_check(k1);
1258         }
1259     };
1260     template <typename U, typename std::enable_if<std::is_integral<typename U::value_type>::value, int>::type = 0>
overflow_checkintegrate_tester1261     static void overflow_check(const U &)
1262     {
1263         using k_type = U;
1264         using T = typename k_type::value_type;
1265         symbol_set vs;
1266         vs.add("a");
1267         vs.add("b");
1268         k_type k1{T(1), std::numeric_limits<T>::max()};
1269         auto ret = k1.integrate(symbol("a"), vs);
1270         BOOST_CHECK_EQUAL(ret.first, T(2));
1271         BOOST_CHECK((ret.second == k_type{T(2), std::numeric_limits<T>::max()}));
1272         BOOST_CHECK_THROW(k1.integrate(symbol("b"), vs), std::invalid_argument);
1273     }
1274     template <typename U, typename std::enable_if<!std::is_integral<typename U::value_type>::value, int>::type = 0>
overflow_checkintegrate_tester1275     static void overflow_check(const U &)
1276     {
1277     }
1278     template <typename T>
operator ()integrate_tester1279     void operator()(const T &)
1280     {
1281         boost::mpl::for_each<size_types>(runner<T>());
1282     }
1283 };
1284 
BOOST_AUTO_TEST_CASE(monomial_integrate_test)1285 BOOST_AUTO_TEST_CASE(monomial_integrate_test)
1286 {
1287     boost::mpl::for_each<expo_types>(integrate_tester());
1288 }
1289 
1290 struct ipow_subs_tester {
1291     template <typename T>
1292     struct runner {
1293         template <typename U>
operator ()ipow_subs_tester::runner1294         void operator()(const U &)
1295         {
1296             typedef monomial<T, U> k_type;
1297             // Test the type trait.
1298             BOOST_CHECK((key_has_ipow_subs<k_type, integer>::value));
1299             BOOST_CHECK((key_has_ipow_subs<k_type, double>::value));
1300             BOOST_CHECK((key_has_ipow_subs<k_type, real>::value));
1301             BOOST_CHECK((key_has_ipow_subs<k_type, rational>::value));
1302             BOOST_CHECK((!key_has_ipow_subs<k_type, std::string>::value));
1303             symbol_set vs;
1304             k_type k1;
1305             auto ret = k1.ipow_subs("x", integer(45), integer(4), vs);
1306             BOOST_CHECK_EQUAL(ret.size(), 1u);
1307             BOOST_CHECK_EQUAL(ret[0u].first, 1);
1308             BOOST_CHECK((std::is_same<integer, decltype(ret[0u].first)>::value));
1309             BOOST_CHECK(ret[0u].second == k1);
1310             vs.add("x");
1311             BOOST_CHECK_THROW(k1.ipow_subs("x", integer(35), integer(4), vs), std::invalid_argument);
1312             k1 = k_type({T(2)});
1313             ret = k1.ipow_subs("y", integer(2), integer(4), vs);
1314             BOOST_CHECK_EQUAL(ret.size(), 1u);
1315             BOOST_CHECK_EQUAL(ret[0u].first, 1);
1316             BOOST_CHECK(ret[0u].second == k1);
1317             ret = k1.ipow_subs("x", integer(1), integer(4), vs);
1318             BOOST_CHECK_EQUAL(ret.size(), 1u);
1319             BOOST_CHECK_EQUAL(ret[0u].first, math::pow(integer(4), T(2)));
1320             BOOST_CHECK(ret[0u].second == k_type({T(0)}));
1321             ret = k1.ipow_subs("x", integer(2), integer(4), vs);
1322             BOOST_CHECK_EQUAL(ret.size(), 1u);
1323             BOOST_CHECK_EQUAL(ret[0u].first, math::pow(integer(4), T(1)));
1324             BOOST_CHECK(ret[0u].second == k_type({T(0)}));
1325             ret = k1.ipow_subs("x", integer(-1), integer(4), vs);
1326             BOOST_CHECK_EQUAL(ret.size(), 1u);
1327             BOOST_CHECK_EQUAL(ret[0u].first, 1);
1328             BOOST_CHECK(ret[0u].second == k_type({T(2)}));
1329             ret = k1.ipow_subs("x", integer(4), integer(4), vs);
1330             BOOST_CHECK_EQUAL(ret.size(), 1u);
1331             BOOST_CHECK_EQUAL(ret[0u].first, 1);
1332             BOOST_CHECK(ret[0u].second == k_type({T(2)}));
1333             k1 = k_type({T(7), T(2)});
1334             BOOST_CHECK_THROW(k1.ipow_subs("x", integer(4), integer(4), vs), std::invalid_argument);
1335             vs.add("y");
1336             ret = k1.ipow_subs("x", integer(3), integer(2), vs);
1337             BOOST_CHECK_EQUAL(ret.size(), 1u);
1338             BOOST_CHECK_EQUAL(ret[0u].first, math::pow(integer(2), T(2)));
1339             BOOST_CHECK((ret[0u].second == k_type{T(1), T(2)}));
1340             ret = k1.ipow_subs("x", integer(4), integer(2), vs);
1341             BOOST_CHECK_EQUAL(ret.size(), 1u);
1342             BOOST_CHECK_EQUAL(ret[0u].first, math::pow(integer(2), T(1)));
1343             BOOST_CHECK((ret[0u].second == k_type{T(3), T(2)}));
1344             ret = k1.ipow_subs("x", integer(-4), integer(2), vs);
1345             BOOST_CHECK_EQUAL(ret.size(), 1u);
1346             BOOST_CHECK_EQUAL(ret[0u].first, 1);
1347             BOOST_CHECK((ret[0u].second == k_type{T(7), T(2)}));
1348             k1 = k_type({T(-7), T(2)});
1349             ret = k1.ipow_subs("x", integer(4), integer(2), vs);
1350             BOOST_CHECK_EQUAL(ret.size(), 1u);
1351             BOOST_CHECK_EQUAL(ret[0u].first, 1);
1352             BOOST_CHECK((ret[0u].second == k_type{T(-7), T(2)}));
1353             ret = k1.ipow_subs("x", integer(-4), integer(2), vs);
1354             BOOST_CHECK_EQUAL(ret.size(), 1u);
1355             BOOST_CHECK_EQUAL(ret[0u].first, math::pow(integer(2), T(1)));
1356             BOOST_CHECK((ret[0u].second == k_type{T(-3), T(2)}));
1357             ret = k1.ipow_subs("x", integer(-3), integer(2), vs);
1358             BOOST_CHECK_EQUAL(ret.size(), 1u);
1359             BOOST_CHECK_EQUAL(ret[0u].first, math::pow(integer(2), T(2)));
1360             BOOST_CHECK((ret[0u].second == k_type{T(-1), T(2)}));
1361             k1 = k_type({T(2), T(-7)});
1362             ret = k1.ipow_subs("y", integer(-3), integer(2), vs);
1363             BOOST_CHECK_EQUAL(ret.size(), 1u);
1364             BOOST_CHECK_EQUAL(ret[0u].first, math::pow(integer(2), T(2)));
1365             BOOST_CHECK((ret[0u].second == k_type{T(2), T(-1)}));
1366             BOOST_CHECK_THROW(k1.ipow_subs("y", integer(0), integer(2), vs), zero_division_error);
1367             k1 = k_type({T(-7), T(2)});
1368             auto ret2 = k1.ipow_subs("x", integer(-4), real(-2.345), vs);
1369             BOOST_CHECK_EQUAL(ret2.size(), 1u);
1370             BOOST_CHECK_EQUAL(ret2[0u].first, math::pow(real(-2.345), T(1)));
1371             BOOST_CHECK((ret2[0u].second == k_type{T(-3), T(2)}));
1372             BOOST_CHECK((std::is_same<real, decltype(ret2[0u].first)>::value));
1373             auto ret3 = k1.ipow_subs("x", integer(-3), rational(-1, 2), vs);
1374             BOOST_CHECK_EQUAL(ret3.size(), 1u);
1375             BOOST_CHECK_EQUAL(ret3[0u].first, math::pow(rational(-1, 2), T(2)));
1376             BOOST_CHECK((ret3[0u].second == k_type{T(-1), T(2)}));
1377             BOOST_CHECK((std::is_same<rational, decltype(ret3[0u].first)>::value));
1378         }
1379     };
1380     template <typename T>
operator ()ipow_subs_tester1381     void operator()(const T &)
1382     {
1383         boost::mpl::for_each<size_types>(runner<T>());
1384     }
1385 };
1386 
BOOST_AUTO_TEST_CASE(monomial_ipow_subs_test)1387 BOOST_AUTO_TEST_CASE(monomial_ipow_subs_test)
1388 {
1389     boost::mpl::for_each<expo_types>(ipow_subs_tester());
1390 }
1391 
1392 struct tt_tester {
1393     template <typename T>
1394     struct runner {
1395         template <typename U>
operator ()tt_tester::runner1396         void operator()(const U &)
1397         {
1398             typedef monomial<T, U> k_type;
1399             BOOST_CHECK((!key_has_t_subs<k_type, int, int>::value));
1400             BOOST_CHECK((!key_has_t_subs<k_type &, int, int>::value));
1401             BOOST_CHECK((!key_has_t_subs<k_type &&, int, int>::value));
1402             BOOST_CHECK((!key_has_t_subs<const k_type &, int, int>::value));
1403             BOOST_CHECK(is_container_element<k_type>::value);
1404             BOOST_CHECK(is_hashable<k_type>::value);
1405             BOOST_CHECK(key_has_degree<k_type>::value);
1406             BOOST_CHECK(key_has_ldegree<k_type>::value);
1407             BOOST_CHECK(!key_has_t_degree<k_type>::value);
1408             BOOST_CHECK(!key_has_t_ldegree<k_type>::value);
1409             BOOST_CHECK(!key_has_t_order<k_type>::value);
1410             BOOST_CHECK(!key_has_t_lorder<k_type>::value);
1411         }
1412     };
1413     template <typename T>
operator ()tt_tester1414     void operator()(const T &)
1415     {
1416         boost::mpl::for_each<size_types>(runner<T>());
1417     }
1418 };
1419 
BOOST_AUTO_TEST_CASE(monomial_type_traits_test)1420 BOOST_AUTO_TEST_CASE(monomial_type_traits_test)
1421 {
1422     boost::mpl::for_each<expo_types>(tt_tester());
1423 }
1424 
BOOST_AUTO_TEST_CASE(monomial_kic_test)1425 BOOST_AUTO_TEST_CASE(monomial_kic_test)
1426 {
1427     using k_type_00 = monomial<int>;
1428     using k_type_01 = monomial<long>;
1429     using k_type_02 = monomial<long>;
1430     BOOST_CHECK((key_is_convertible<k_type_00, k_type_00>::value));
1431     BOOST_CHECK((key_is_convertible<k_type_01, k_type_01>::value));
1432     BOOST_CHECK((key_is_convertible<k_type_02, k_type_02>::value));
1433     BOOST_CHECK((key_is_convertible<k_type_00, k_type_01>::value));
1434     BOOST_CHECK((key_is_convertible<k_type_01, k_type_00>::value));
1435     BOOST_CHECK((key_is_convertible<k_type_00, k_type_02>::value));
1436     BOOST_CHECK((key_is_convertible<k_type_02, k_type_00>::value));
1437     BOOST_CHECK((key_is_convertible<k_type_01, k_type_02>::value));
1438     BOOST_CHECK((key_is_convertible<k_type_02, k_type_01>::value));
1439     BOOST_CHECK((!key_is_convertible<k_type_00, k_monomial>::value));
1440     BOOST_CHECK((!key_is_convertible<k_monomial, k_type_00>::value));
1441 }
1442 
BOOST_AUTO_TEST_CASE(monomial_comparison_test)1443 BOOST_AUTO_TEST_CASE(monomial_comparison_test)
1444 {
1445     using k_type_00 = monomial<int>;
1446     BOOST_CHECK(is_less_than_comparable<k_type_00>::value);
1447     BOOST_CHECK(!(k_type_00{} < k_type_00{}));
1448     BOOST_CHECK(!(k_type_00{3} < k_type_00{2}));
1449     BOOST_CHECK(!(k_type_00{3} < k_type_00{3}));
1450     BOOST_CHECK(k_type_00{2} < k_type_00{3});
1451     BOOST_CHECK((k_type_00{2, 3} < k_type_00{2, 4}));
1452     BOOST_CHECK(!(k_type_00{2, 2} < k_type_00{2, 2}));
1453     BOOST_CHECK((k_type_00{1, 3} < k_type_00{2, 1}));
1454     BOOST_CHECK(!(k_type_00{1, 2, 3, 4} < k_type_00{1, 2, 3, 4}));
1455     BOOST_CHECK_THROW((void)(k_type_00{} < k_type_00{1}), std::invalid_argument);
1456     BOOST_CHECK_THROW((void)(k_type_00{1} < k_type_00{}), std::invalid_argument);
1457 }
1458 
1459 struct split_tester {
1460     template <typename T>
1461     struct runner {
1462         template <typename U>
operator ()split_tester::runner1463         void operator()(const U &)
1464         {
1465             using k_type = monomial<T, U>;
1466             symbol_set vs;
1467             BOOST_CHECK_THROW(k_type{}.split(vs), std::invalid_argument);
1468             vs.add("x");
1469             BOOST_CHECK_THROW(k_type{}.split(vs), std::invalid_argument);
1470             BOOST_CHECK_THROW(k_type{T(1)}.split(vs), std::invalid_argument);
1471             vs.add("y");
1472             auto res = k_type{T(1), T(2)}.split(vs);
1473             BOOST_CHECK_EQUAL(res.first.size(), 1u);
1474             BOOST_CHECK_EQUAL(res.first[0u], T(2));
1475             BOOST_CHECK_EQUAL(res.second.size(), 1u);
1476             BOOST_CHECK_EQUAL(res.second[0u], T(1));
1477             vs.add("z");
1478             BOOST_CHECK_THROW((k_type{T(1), T(2)}.split(vs)), std::invalid_argument);
1479             res = k_type{T(1), T(2), T(3)}.split(vs);
1480             BOOST_CHECK_EQUAL(res.first.size(), 2u);
1481             BOOST_CHECK_EQUAL(res.first[0u], T(2));
1482             BOOST_CHECK_EQUAL(res.first[1u], T(3));
1483             BOOST_CHECK_EQUAL(res.second.size(), 1u);
1484             BOOST_CHECK_EQUAL(res.second[0u], T(1));
1485         }
1486     };
1487     template <typename T>
operator ()split_tester1488     void operator()(const T &)
1489     {
1490         boost::mpl::for_each<size_types>(runner<T>());
1491     }
1492 };
1493 
BOOST_AUTO_TEST_CASE(monomial_split_test)1494 BOOST_AUTO_TEST_CASE(monomial_split_test)
1495 {
1496     boost::mpl::for_each<expo_types>(split_tester());
1497 }
1498 
1499 struct extract_exponents_tester {
1500     template <typename T>
1501     struct runner {
1502         template <typename U>
operator ()extract_exponents_tester::runner1503         void operator()(const U &)
1504         {
1505             using key_type = monomial<T, U>;
1506             std::vector<T> out;
1507             key_type k{};
1508             symbol_set ss;
1509             k.extract_exponents(out, ss);
1510             BOOST_CHECK_EQUAL(out.size(), 0u);
1511             ss.add(symbol{"a"});
1512             BOOST_CHECK_THROW(k.extract_exponents(out, ss), std::invalid_argument);
1513             BOOST_CHECK_EQUAL(out.size(), 0u);
1514             k = key_type{T(-2)};
1515             k.extract_exponents(out, ss);
1516             BOOST_CHECK_EQUAL(out.size(), 1u);
1517             BOOST_CHECK_EQUAL(out[0u], T(-2));
1518             ss.add(symbol{"b"});
1519             BOOST_CHECK_THROW(k.extract_exponents(out, ss), std::invalid_argument);
1520             BOOST_CHECK_EQUAL(out.size(), 1u);
1521             BOOST_CHECK_EQUAL(out[0u], T(-2));
1522             k = key_type{T(-2), T(3)};
1523             out.resize(4u);
1524             k.extract_exponents(out, ss);
1525             BOOST_CHECK_EQUAL(out.size(), 2u);
1526             BOOST_CHECK_EQUAL(out[0u], T(-2));
1527             BOOST_CHECK_EQUAL(out[1u], T(3));
1528         }
1529     };
1530     template <typename T>
operator ()extract_exponents_tester1531     void operator()(const T &)
1532     {
1533         boost::mpl::for_each<size_types>(runner<T>());
1534     }
1535 };
1536 
BOOST_AUTO_TEST_CASE(monomial_extract_exponents_test)1537 BOOST_AUTO_TEST_CASE(monomial_extract_exponents_test)
1538 {
1539     boost::mpl::for_each<expo_types>(extract_exponents_tester());
1540 }
1541 
1542 struct has_negative_exponent_tester {
1543     template <typename T>
1544     struct runner {
1545         template <typename U>
operator ()has_negative_exponent_tester::runner1546         void operator()(const U &)
1547         {
1548             using key_type = monomial<T, U>;
1549             key_type k{};
1550             symbol_set ss;
1551             BOOST_CHECK(!k.has_negative_exponent(ss));
1552             ss.add("x");
1553             BOOST_CHECK_THROW(k.has_negative_exponent(ss), std::invalid_argument);
1554             k = key_type{T(1)};
1555             BOOST_CHECK(!k.has_negative_exponent(ss));
1556             k = key_type{T(0)};
1557             BOOST_CHECK(!k.has_negative_exponent(ss));
1558             k = key_type{T(-1)};
1559             BOOST_CHECK(k.has_negative_exponent(ss));
1560             ss.add("y");
1561             BOOST_CHECK_THROW(k.has_negative_exponent(ss), std::invalid_argument);
1562             k = key_type{T(0), T(1)};
1563             BOOST_CHECK(!k.has_negative_exponent(ss));
1564             k = key_type{T(0), T(-1)};
1565             BOOST_CHECK(k.has_negative_exponent(ss));
1566         }
1567     };
1568     template <typename T>
operator ()has_negative_exponent_tester1569     void operator()(const T &)
1570     {
1571         boost::mpl::for_each<size_types>(runner<T>());
1572     }
1573 };
1574 
BOOST_AUTO_TEST_CASE(monomial_has_negative_exponent_test)1575 BOOST_AUTO_TEST_CASE(monomial_has_negative_exponent_test)
1576 {
1577     boost::mpl::for_each<expo_types>(has_negative_exponent_tester());
1578 }
1579