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/real_trigonometric_kronecker_monomial.hpp"
30
31 #define BOOST_TEST_MODULE real_trigonometric_kronecker_monomial_02_test
32 #include <boost/test/included/unit_test.hpp>
33
34 #include <algorithm>
35 #include <boost/algorithm/string/predicate.hpp>
36 #include <boost/archive/xml_iarchive.hpp>
37 #include <boost/archive/xml_oarchive.hpp>
38 #include <initializer_list>
39 #include <mutex>
40 #include <random>
41 #include <sstream>
42 #include <stdexcept>
43 #include <string>
44 #include <thread>
45 #include <tuple>
46 #include <vector>
47
48 #include "../src/init.hpp"
49 #include "../src/s11n.hpp"
50 #include "../src/symbol_set.hpp"
51 #include "../src/type_traits.hpp"
52
53 using namespace piranha;
54
55 using int_types = std::tuple<signed char, int, long, long long>;
56
57 static const int ntries = 1000;
58
59 static std::mutex mut;
60
61 template <typename OArchive, typename IArchive, typename T>
boost_roundtrip(const T & x,const symbol_set & args,bool mt=false)62 static inline void boost_roundtrip(const T &x, const symbol_set &args, bool mt = false)
63 {
64 using w_type = boost_s11n_key_wrapper<T>;
65 {
66 std::stringstream ss;
67 {
68 OArchive oa(ss);
69 boost_save(oa, w_type{x, args});
70 }
71 T retval;
72 {
73 IArchive ia(ss);
74 w_type w{retval, args};
75 boost_load(ia, w);
76 }
77 if (mt) {
78 std::lock_guard<std::mutex> lock(mut);
79 BOOST_CHECK(x == retval);
80 } else {
81 BOOST_CHECK(x == retval);
82 }
83 }
84 {
85 std::stringstream ss;
86 {
87 OArchive oa(ss);
88 w_type w{x, args};
89 oa << w;
90 }
91 T retval;
92 {
93 IArchive ia(ss);
94 w_type w{retval, args};
95 ia >> w;
96 }
97 if (mt) {
98 std::lock_guard<std::mutex> lock(mut);
99 BOOST_CHECK(x == retval);
100 } else {
101 BOOST_CHECK(x == retval);
102 }
103 }
104 }
105
106 struct boost_s11n_tester {
107 template <typename T>
operator ()boost_s11n_tester108 void operator()(const T &) const
109 {
110 using k_type = real_trigonometric_kronecker_monomial<T>;
111 using w_type = boost_s11n_key_wrapper<k_type>;
112 BOOST_CHECK((has_boost_save<boost::archive::binary_oarchive, w_type>::value));
113 BOOST_CHECK((has_boost_save<boost::archive::text_oarchive, w_type>::value));
114 BOOST_CHECK((has_boost_load<boost::archive::binary_iarchive, w_type>::value));
115 BOOST_CHECK((has_boost_load<boost::archive::text_iarchive, w_type>::value));
116 BOOST_CHECK((has_boost_save<boost::archive::xml_oarchive, w_type>::value));
117 BOOST_CHECK((has_boost_load<boost::archive::xml_iarchive, w_type>::value));
118 BOOST_CHECK((!has_boost_save<boost::archive::text_iarchive, w_type>::value));
119 BOOST_CHECK((!has_boost_load<boost::archive::text_oarchive, w_type>::value));
120 BOOST_CHECK((!has_boost_save<boost::archive::binary_oarchive const, w_type>::value));
121 BOOST_CHECK((!has_boost_save<void, w_type>::value));
122 BOOST_CHECK((!has_boost_load<boost::archive::binary_iarchive const, w_type>::value));
123 BOOST_CHECK((!has_boost_load<void, w_type>::value));
124 const std::vector<std::string> names = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "l"};
125 auto t_func = [&names](unsigned n) {
126 std::uniform_int_distribution<unsigned> sdist(0, 10);
127 std::uniform_int_distribution<int> edist(-10, 10);
128 std::uniform_int_distribution<int> fdist(0, 1);
129 std::mt19937 rng(n);
130 std::vector<T> expos;
131 for (int i = 0; i < ntries; ++i) {
132 auto s = sdist(rng);
133 expos.resize(s);
134 std::generate(expos.begin(), expos.end(), [&rng, &edist]() { return edist(rng); });
135 k_type k;
136 try {
137 k = k_type(expos.begin(), expos.end());
138 } catch (...) {
139 continue;
140 }
141 k.set_flavour(static_cast<bool>(fdist(rng)));
142 boost_roundtrip<boost::archive::text_oarchive, boost::archive::text_iarchive>(
143 k, symbol_set(names.begin(), names.begin() + s), true);
144 boost_roundtrip<boost::archive::binary_oarchive, boost::archive::binary_iarchive>(
145 k, symbol_set(names.begin(), names.begin() + s), true);
146 }
147 };
148 std::thread t0(t_func, 0);
149 std::thread t1(t_func, 1);
150 std::thread t2(t_func, 2);
151 std::thread t3(t_func, 3);
152 t0.join();
153 t1.join();
154 t2.join();
155 t3.join();
156 // Test inconsistent size.
157 {
158 std::stringstream ss;
159 {
160 boost::archive::text_oarchive oa(ss);
161 boost_save(oa, w_type{k_type{}, symbol_set{}});
162 }
163 k_type retval{T(1), T(2)};
164 {
165 boost::archive::text_iarchive ia(ss);
166 symbol_set new_ss{symbol{"x"}};
167 w_type w{retval, new_ss};
168 BOOST_CHECK_EXCEPTION(boost_load(ia, w), std::invalid_argument, [](const std::invalid_argument &iae) {
169 return boost::contains(
170 iae.what(),
171 "invalid size detected in the deserialization of a real Kronercker "
172 "trigonometric monomial: the deserialized size is 0 but the reference symbol set has a "
173 "size of 1");
174 });
175 }
176 BOOST_CHECK((retval == k_type{T(1), T(2)}));
177 }
178 }
179 };
180
BOOST_AUTO_TEST_CASE(rtkm_constructor_test)181 BOOST_AUTO_TEST_CASE(rtkm_constructor_test)
182 {
183 init();
184 tuple_for_each(int_types{}, boost_s11n_tester());
185 }
186
187 #if defined(PIRANHA_WITH_MSGPACK)
188
189 template <typename T>
msgpack_roundtrip(const T & x,const symbol_set & args,msgpack_format f,bool mt=false)190 static inline void msgpack_roundtrip(const T &x, const symbol_set &args, msgpack_format f, bool mt = false)
191 {
192 msgpack::sbuffer sbuf;
193 msgpack::packer<msgpack::sbuffer> p(sbuf);
194 x.msgpack_pack(p, f, args);
195 T retval;
196 auto oh = msgpack::unpack(sbuf.data(), sbuf.size());
197 retval.msgpack_convert(oh.get(), f, args);
198 if (mt) {
199 std::lock_guard<std::mutex> lock(mut);
200 BOOST_CHECK(x == retval);
201 } else {
202 BOOST_CHECK(x == retval);
203 }
204 }
205
206 struct msgpack_s11n_tester {
207 template <typename T>
operator ()msgpack_s11n_tester208 void operator()(const T &) const
209 {
210 using k_type = real_trigonometric_kronecker_monomial<T>;
211 BOOST_CHECK((key_has_msgpack_pack<msgpack::sbuffer, k_type>::value));
212 BOOST_CHECK((!key_has_msgpack_pack<msgpack::sbuffer &, k_type>::value));
213 BOOST_CHECK((!key_has_msgpack_pack<int, k_type>::value));
214 BOOST_CHECK((!key_has_msgpack_pack<void, k_type>::value));
215 BOOST_CHECK((key_has_msgpack_convert<k_type>::value));
216 BOOST_CHECK((!key_has_msgpack_convert<k_type const &>::value));
217 const std::vector<std::string> names = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "l"};
218 auto t_func = [&names](unsigned n) {
219 std::uniform_int_distribution<unsigned> sdist(0, 10);
220 std::uniform_int_distribution<int> edist(-10, 10);
221 std::uniform_int_distribution<int> fdist(0, 1);
222 std::mt19937 rng(n);
223 std::vector<T> expos;
224 for (auto f : {msgpack_format::portable, msgpack_format::binary}) {
225 for (int i = 0; i < ntries; ++i) {
226 auto s = sdist(rng);
227 expos.resize(s);
228 std::generate(expos.begin(), expos.end(), [&rng, &edist]() { return edist(rng); });
229 k_type k;
230 try {
231 k = k_type(expos.begin(), expos.end());
232 } catch (...) {
233 continue;
234 }
235 k.set_flavour(fdist(rng));
236 msgpack_roundtrip(k, symbol_set(names.begin(), names.begin() + s), f, true);
237 }
238 }
239 };
240 std::thread t0(t_func, 0);
241 std::thread t1(t_func, 1);
242 std::thread t2(t_func, 2);
243 std::thread t3(t_func, 3);
244 t0.join();
245 t1.join();
246 t2.join();
247 t3.join();
248 // Test inconsistent size.
249 {
250 msgpack::sbuffer sbuf;
251 msgpack::packer<msgpack::sbuffer> p(sbuf);
252 p.pack_array(2);
253 p.pack_array(1);
254 msgpack_pack(p, T(1), msgpack_format::portable);
255 msgpack_pack(p, true, msgpack_format::portable);
256 k_type retval{T(2)};
257 auto oh = msgpack::unpack(sbuf.data(), sbuf.size());
258 BOOST_CHECK_EXCEPTION(
259 retval.msgpack_convert(oh.get(), msgpack_format::portable, symbol_set{}), std::invalid_argument,
260 [](const std::invalid_argument &ia) {
261 return boost::contains(
262 ia.what(),
263 "incompatible symbol set in trigonometric monomial serialization: the reference "
264 "symbol set has a size of 0, while the trigonometric monomial being deserialized has "
265 "a size of 1");
266 });
267 BOOST_CHECK((retval == k_type{T(2)}));
268 }
269 }
270 };
271
BOOST_AUTO_TEST_CASE(kronecker_monomial_msgpack_s11n_test)272 BOOST_AUTO_TEST_CASE(kronecker_monomial_msgpack_s11n_test)
273 {
274 tuple_for_each(int_types{}, msgpack_s11n_tester());
275 }
276
277 #endif
278