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