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/power_series.hpp"
30 
31 #define BOOST_TEST_MODULE power_series_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 <string>
37 #include <type_traits>
38 #include <vector>
39 
40 #include "../src/init.hpp"
41 #include "../src/math.hpp"
42 #include "../src/monomial.hpp"
43 #include "../src/mp_integer.hpp"
44 #include "../src/mp_rational.hpp"
45 #include "../src/poisson_series.hpp"
46 #include "../src/polynomial.hpp"
47 #include "../src/real.hpp"
48 #include "../src/real_trigonometric_kronecker_monomial.hpp"
49 #include "../src/series.hpp"
50 
51 using namespace piranha;
52 
53 typedef boost::mpl::vector<double, integer> cf_types;
54 typedef boost::mpl::vector<int, integer> expo_types;
55 
56 template <typename Cf, typename Expo>
57 class g_series_type : public power_series<series<Cf, monomial<Expo>, g_series_type<Cf, Expo>>, g_series_type<Cf, Expo>>
58 {
59     using base = power_series<series<Cf, monomial<Expo>, g_series_type<Cf, Expo>>, g_series_type<Cf, Expo>>;
60 
61 public:
62     g_series_type() = default;
63     g_series_type(const g_series_type &) = default;
64     g_series_type(g_series_type &&) = default;
65     g_series_type &operator=(const g_series_type &) = default;
66     g_series_type &operator=(g_series_type &&) = default;
67     PIRANHA_FORWARDING_CTOR(g_series_type, base)
68     PIRANHA_FORWARDING_ASSIGNMENT(g_series_type, base)
69 };
70 
71 template <typename Cf>
72 class g_series_type2 : public power_series<series<Cf, rtk_monomial, g_series_type2<Cf>>, g_series_type2<Cf>>
73 {
74     typedef power_series<series<Cf, rtk_monomial, g_series_type2<Cf>>, g_series_type2<Cf>> base;
75 
76 public:
77     g_series_type2() = default;
78     g_series_type2(const g_series_type2 &) = default;
79     g_series_type2(g_series_type2 &&) = default;
80     g_series_type2 &operator=(const g_series_type2 &) = default;
81     g_series_type2 &operator=(g_series_type2 &&) = default;
82     PIRANHA_FORWARDING_CTOR(g_series_type2, base)
83     PIRANHA_FORWARDING_ASSIGNMENT(g_series_type2, base)
84 };
85 
86 struct degree_tester {
87     template <typename Cf>
88     struct runner {
89         template <typename Expo>
operator ()degree_tester::runner90         void operator()(const Expo &)
91         {
92             typedef polynomial<Cf, monomial<Expo>> p_type1;
93             typedef polynomial<polynomial<Cf, monomial<Expo>>, monomial<Expo>> p_type11;
94             using deg_type = typename std::conditional<std::is_same<Expo, int>::value, int, integer>::type;
95             BOOST_CHECK((std::is_same<deg_type, decltype(math::degree(p_type1{}))>::value));
96             BOOST_CHECK((std::is_same<deg_type, decltype(math::degree(p_type1{}, std::vector<std::string>{}))>::value));
97             BOOST_CHECK((std::is_same<deg_type, decltype(math::ldegree(p_type1{}))>::value));
98             BOOST_CHECK(
99                 (std::is_same<deg_type, decltype(math::ldegree(p_type1{}, std::vector<std::string>{}))>::value));
100             BOOST_CHECK(math::degree(p_type1{}) == 0);
101             BOOST_CHECK(math::degree(p_type1{}, std::vector<std::string>{}) == 0);
102             BOOST_CHECK(math::ldegree(p_type1{}) == 0);
103             BOOST_CHECK(math::ldegree(p_type1{}, std::vector<std::string>{}) == 0);
104             BOOST_CHECK(math::degree(p_type1{"x"}) == 1);
105             BOOST_CHECK(math::degree(p_type1{"x"}, {"x"}) == 1);
106             BOOST_CHECK(math::degree(p_type1{"x"}, {"y"}) == 0);
107             BOOST_CHECK(math::ldegree(p_type1{"x"}) == 1);
108             BOOST_CHECK(math::ldegree(p_type1{"x"}, {"x"}) == 1);
109             BOOST_CHECK(math::ldegree(p_type1{"x"}, {"y"}) == 0);
110             BOOST_CHECK(math::degree(p_type1{"x"} * p_type1{"x"}) == 2);
111             BOOST_CHECK(math::degree(p_type1{"x"} * p_type1{"x"}, {"x"}) == 2);
112             BOOST_CHECK(math::degree(p_type1{"x"} * p_type1{"y"}, {"y"}) == 1);
113             BOOST_CHECK(math::ldegree(p_type1{"x"} * p_type1{"x"}) == 2);
114             BOOST_CHECK(math::ldegree(p_type1{"x"} * p_type1{"x"}, {"x"}) == 2);
115             BOOST_CHECK(math::ldegree(p_type1{"x"} * p_type1{"y"}, {"y"}) == 1);
116             BOOST_CHECK(math::degree(p_type1{"x"} + p_type1{"y"} + p_type1{1}) == 1);
117             BOOST_CHECK(math::degree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"x"}) == 1);
118             BOOST_CHECK(math::degree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"x"}) == 1);
119             BOOST_CHECK(math::degree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"y"}) == 1);
120             BOOST_CHECK(math::degree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"y"}) == 1);
121             BOOST_CHECK(math::degree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"z"}) == 0);
122             BOOST_CHECK(math::degree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"z"}) == 0);
123             BOOST_CHECK(math::ldegree(p_type1{"x"} + p_type1{"y"} + p_type1{1}) == 0);
124             BOOST_CHECK(math::ldegree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"x"}) == 0);
125             BOOST_CHECK(math::ldegree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"x"}) == 0);
126             BOOST_CHECK(math::ldegree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"y"}) == 0);
127             BOOST_CHECK(math::ldegree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"y"}) == 0);
128             BOOST_CHECK(math::ldegree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"z"}) == 0);
129             BOOST_CHECK(math::ldegree(p_type1{"x"} + p_type1{"y"} + p_type1{1}, {"z"}) == 0);
130             BOOST_CHECK(math::ldegree(p_type1{"x"} * p_type1{"x"} + p_type1{"y"} + p_type1{"x"}) == 1);
131             BOOST_CHECK(math::ldegree(p_type1{"x"} * p_type1{"x"} + p_type1{"y"} + p_type1{"x"}, {"x"}) == 0);
132             BOOST_CHECK(math::ldegree(p_type1{"x"} * p_type1{"x"} + p_type1{"y"} + p_type1{"x"}, {"x"}) == 0);
133             BOOST_CHECK(math::ldegree(p_type1{"x"} * p_type1{"x"} + 2 * p_type1{"x"}, {"x"}) == 1);
134             BOOST_CHECK(math::ldegree(p_type1{"x"} * p_type1{"y"} + 2 * p_type1{"x"}, {"x"}) == 1);
135             BOOST_CHECK(math::ldegree(p_type1{"x"} * p_type1{"y"} + 2 * p_type1{"x"}, {"y"}) == 0);
136             std::vector<std::string> empty_set;
137             BOOST_CHECK((std::is_same<decltype(math::degree(std::declval<const p_type11 &>())), deg_type>::value));
138             BOOST_CHECK(
139                 (std::is_same<decltype(math::degree(std::declval<const p_type11 &>(), empty_set)), deg_type>::value));
140             BOOST_CHECK((std::is_same<decltype(math::ldegree(std::declval<const p_type11 &>())), deg_type>::value));
141             BOOST_CHECK(
142                 (std::is_same<decltype(math::ldegree(std::declval<const p_type11 &>(), empty_set)), deg_type>::value));
143             BOOST_CHECK(math::degree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"}) == 2);
144             BOOST_CHECK(math::degree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"}, {"x"}) == 1);
145             BOOST_CHECK(math::degree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"}, {"x"}) == 1);
146             BOOST_CHECK(math::degree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"}, {"y"}) == 1);
147             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"}) == 1);
148             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"}, {"y"}) == 1);
149             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"}, {"y"}) == 1);
150             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"}, {"z"}) == 0);
151             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"}, {"z"}) == 0);
152             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"} + 1) == 0);
153             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"} + 1, {"x"}) == 0);
154             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} + 2 * p_type1{"y"} + 1, {"y"}) == 0);
155             BOOST_CHECK(math::degree(p_type11{"x"} * p_type1{"y"} * p_type1{"y"} + 2 * p_type1{"y"} + 1) == 3);
156             BOOST_CHECK(math::degree(p_type11{"x"} * p_type1{"y"} * p_type1{"y"} + 2 * p_type1{"y"} + 1, {"x"}) == 1);
157             BOOST_CHECK(math::degree(p_type11{"x"} * p_type1{"y"} * p_type1{"y"} + 2 * p_type1{"y"} + 1, {"y"}) == 2);
158             BOOST_CHECK(math::degree(p_type11{"x"} * p_type1{"y"} * p_type1{"y"} + 2 * p_type1{"y"} + 1, {"y"}) == 2);
159             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} * p_type1{"y"} + 2 * p_type1{"y"} + 1) == 0);
160             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} * p_type1{"y"} + 2 * p_type1{"y"}, {"x"}) == 0);
161             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} * p_type1{"y"} + 2 * p_type1{"y"}, {"y"}) == 1);
162             BOOST_CHECK(math::ldegree(p_type11{"x"} * p_type1{"y"} * p_type1{"y"} + 2 * p_type1{"y"}, {"y"}) == 1);
163             // Test the type traits.
164             BOOST_CHECK(has_degree<p_type1>::value);
165             BOOST_CHECK(has_degree<p_type11>::value);
166             BOOST_CHECK(has_ldegree<p_type1>::value);
167             BOOST_CHECK(has_ldegree<p_type11>::value);
168             // Poisson series tests.
169             typedef poisson_series<p_type1> pstype1;
170             BOOST_CHECK(has_degree<pstype1>::value);
171             BOOST_CHECK(has_ldegree<pstype1>::value);
172             typedef poisson_series<Cf> pstype2;
173             BOOST_CHECK(!has_degree<pstype2>::value);
174             BOOST_CHECK(!has_ldegree<pstype2>::value);
175             BOOST_CHECK((std::is_same<deg_type, decltype(math::degree(pstype1{}))>::value));
176             BOOST_CHECK((std::is_same<deg_type, decltype(math::degree(pstype1{}, std::vector<std::string>{}))>::value));
177             BOOST_CHECK((std::is_same<deg_type, decltype(math::ldegree(pstype1{}))>::value));
178             BOOST_CHECK(
179                 (std::is_same<deg_type, decltype(math::ldegree(pstype1{}, std::vector<std::string>{}))>::value));
180             // As usual, operations on Poisson series with (polynomial) integer coefficients are not gonna give
181             // meaningful mathematical results.
182             if (std::is_same<Cf, integer>::value) {
183                 return;
184             }
185             BOOST_CHECK(math::degree(pstype1{}) == 0);
186             BOOST_CHECK(math::degree(pstype1{}, std::vector<std::string>{}) == 0);
187             BOOST_CHECK(math::ldegree(pstype1{}) == 0);
188             BOOST_CHECK(math::ldegree(pstype1{}, std::vector<std::string>{}) == 0);
189             BOOST_CHECK(math::degree(pstype1{"x"}) == 1);
190             BOOST_CHECK(math::degree(pstype1{"x"}, {"x"}) == 1);
191             BOOST_CHECK(math::degree(pstype1{"x"}, {"y"}) == 0);
192             BOOST_CHECK(math::ldegree(pstype1{"x"}) == 1);
193             BOOST_CHECK(math::ldegree(pstype1{"x"}, {"x"}) == 1);
194             BOOST_CHECK(math::ldegree(pstype1{"x"}, {"y"}) == 0);
195             BOOST_CHECK(math::degree(pstype1{"x"} * pstype1{"x"}) == 2);
196             BOOST_CHECK(math::degree(pstype1{"x"} * pstype1{"x"}, {"x"}) == 2);
197             BOOST_CHECK(math::degree(pstype1{"x"} * pstype1{"y"}, {"y"}) == 1);
198             BOOST_CHECK(math::ldegree(pstype1{"x"} * pstype1{"x"}) == 2);
199             BOOST_CHECK(math::ldegree(pstype1{"x"} * pstype1{"x"}, {"x"}) == 2);
200             BOOST_CHECK(math::ldegree(pstype1{"x"} * pstype1{"y"}, {"y"}) == 1);
201             BOOST_CHECK(math::degree(pstype1{"x"} + pstype1{"y"} + pstype1{1}) == 1);
202             BOOST_CHECK(math::degree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"x"}) == 1);
203             BOOST_CHECK(math::degree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"x"}) == 1);
204             BOOST_CHECK(math::degree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"y"}) == 1);
205             BOOST_CHECK(math::degree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"y"}) == 1);
206             BOOST_CHECK(math::degree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"z"}) == 0);
207             BOOST_CHECK(math::degree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"z"}) == 0);
208             BOOST_CHECK(math::ldegree(pstype1{"x"} + pstype1{"y"} + pstype1{1}) == 0);
209             BOOST_CHECK(math::ldegree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"x"}) == 0);
210             BOOST_CHECK(math::ldegree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"x"}) == 0);
211             BOOST_CHECK(math::ldegree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"y"}) == 0);
212             BOOST_CHECK(math::ldegree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"y"}) == 0);
213             BOOST_CHECK(math::ldegree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"z"}) == 0);
214             BOOST_CHECK(math::ldegree(pstype1{"x"} + pstype1{"y"} + pstype1{1}, {"z"}) == 0);
215             BOOST_CHECK(math::ldegree(pstype1{"x"} * pstype1{"x"} + pstype1{"y"} + pstype1{"x"}) == 1);
216             BOOST_CHECK(math::ldegree(pstype1{"x"} * pstype1{"x"} + pstype1{"y"} + pstype1{"x"}, {"x"}) == 0);
217             BOOST_CHECK(math::ldegree(pstype1{"x"} * pstype1{"x"} + pstype1{"y"} + pstype1{"x"}, {"x"}) == 0);
218             BOOST_CHECK(math::ldegree(pstype1{"x"} * pstype1{"x"} + 2 * pstype1{"x"}, {"x"}) == 1);
219             BOOST_CHECK(math::ldegree(pstype1{"x"} * pstype1{"y"} + 2 * pstype1{"x"}, {"x"}) == 1);
220             BOOST_CHECK(math::ldegree(pstype1{"x"} * pstype1{"y"} + 2 * pstype1{"x"}, {"y"}) == 0);
221         }
222     };
223     template <typename Cf>
operator ()degree_tester224     void operator()(const Cf &)
225     {
226         boost::mpl::for_each<expo_types>(runner<Cf>());
227     }
228 };
229 
BOOST_AUTO_TEST_CASE(power_series_test_01)230 BOOST_AUTO_TEST_CASE(power_series_test_01)
231 {
232     init();
233     boost::mpl::for_each<cf_types>(degree_tester());
234 }
235