1 /*
2 Copyright (C) 2013 Tom Bachmann
3
4 This file is part of FLINT.
5
6 FLINT is free software: you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License (LGPL) as published
8 by the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version. See <http://www.gnu.org/licenses/>.
10 */
11
12 #ifndef CXX_FMPQXX_H
13 #define CXX_FMPQXX_H
14
15 #include <cstdlib>
16
17 #include "fmpq.h"
18
19 #include "flintxx/expression.h"
20 #include "flintxx/flint_classes.h"
21 #include "flintxx/flint_exception.h"
22 #include "flintxx/frandxx.h"
23 #include "fmpzxx.h"
24
25 // TODO exhibit this as a specialisation of a generic fraction<fmpzxx>
26 // TODO summation
27
28 namespace flint {
29 // function "declarations"
30 FLINT_DEFINE_BINOP(fmpqxx_reconstruct)
FLINT_DEFINE_FOURARY_HERE(fmpqxx_reconstruct)31 FLINT_DEFINE_FOURARY_HERE(fmpqxx_reconstruct) // four argument version
32 FLINT_DEFINE_UNOP(fmpqxx_next_minimal)
33 FLINT_DEFINE_UNOP(fmpqxx_next_signed_minimal)
34 FLINT_DEFINE_UNOP(fmpqxx_next_calkin_wilf)
35 FLINT_DEFINE_UNOP(fmpqxx_next_signed_calkin_wilf)
36 FLINT_DEFINE_UNOP(fmpqxx_num)
37 FLINT_DEFINE_UNOP(fmpqxx_den)
38
39 namespace detail {
40 template<class Fmpq>
41 struct fmpq_traits {
42 typedef FLINT_UNOP_BUILD_RETTYPE(fmpqxx_num, fmpzxx, Fmpq) numreturn_t;
43 typedef FLINT_UNOP_BUILD_RETTYPE(fmpqxx_den, fmpzxx, Fmpq) denreturn_t;
44 typedef numreturn_t cnumreturn_t;
45 typedef denreturn_t cdenreturn_t;
46 static numreturn_t num(const Fmpq& f) {return fmpqxx_num(f);}
47 static denreturn_t den(const Fmpq& f) {return fmpqxx_den(f);}
48 };
49 }
50
51 template<class Operation, class Data>
52 class fmpqxx_expression
53 : public expression<derived_wrapper<fmpqxx_expression>, Operation, Data>
54 {
55 public:
56 typedef expression<derived_wrapper< ::flint::fmpqxx_expression>,
57 Operation, Data> base_t;
58
59 FLINTXX_DEFINE_BASICS(fmpqxx_expression)
FLINTXX_DEFINE_CTORS(fmpqxx_expression)60 FLINTXX_DEFINE_CTORS(fmpqxx_expression)
61 FLINTXX_DEFINE_C_REF(fmpqxx_expression, fmpq, _fmpq)
62
63 // static methods which only make sense with fmpqxx
64 FLINTXX_DEFINE_RANDFUNC(fmpq, randbits)
65 FLINTXX_DEFINE_RANDFUNC(fmpq, randtest)
66 FLINTXX_DEFINE_RANDFUNC(fmpq, randtest_not_zero)
67
68 template<class Vec>
69 static fmpqxx_expression from_cfrac(const Vec& v, slong n)
70 {
71 fmpqxx_expression res;
72 res.set_cfrac(v, n);
73 return res;
74 }
75
76 // TODO does this make more sense as standalone function?
77 template<class Fmpz1, class Fmpz2>
FLINT_BINOP_ENABLE_RETTYPE(fmpqxx_reconstruct,Fmpz1,Fmpz2)78 static FLINT_BINOP_ENABLE_RETTYPE(fmpqxx_reconstruct, Fmpz1, Fmpz2)
79 reconstruct(const Fmpz1& a, const Fmpz2& m)
80 {
81 return fmpqxx_reconstruct(a, m);
82 }
83 template<class Fmpz1, class Fmpz2, class Fmpz3, class Fmpz4>
FLINT_FOURARY_ENABLE_RETTYPE(fmpqxx_reconstruct,Fmpz1,Fmpz2,Fmpz3,Fmpz4)84 static FLINT_FOURARY_ENABLE_RETTYPE(fmpqxx_reconstruct,
85 Fmpz1, Fmpz2, Fmpz3, Fmpz4)
86 reconstruct(const Fmpz1& a, const Fmpz2& m, const Fmpz3& N, const Fmpz4& D)
87 {
88 return fmpqxx_reconstruct(a, m, N, D);
89 }
90
91 template<class F1, class F2>
set_frac(const F1 & f1,const F2 & f2)92 void set_frac(const F1& f1, const F2& f2)
93 {
94 num() = f1;
95 den() = f2;
96 canonicalise();
97 }
98 template<class F1, class F2>
frac(const F1 & f1,const F2 & f2)99 static fmpqxx_expression frac(const F1& f1, const F2& f2)
100 {
101 fmpqxx_expression res;
102 res.set_frac(f1, f2);
103 return res;
104 }
105
106 template<class T>
set_integer(const T & t)107 void set_integer(const T& t)
108 {
109 num() = t;
110 den() = 1u;
111 }
112 template<class T>
integer(const T & t)113 static fmpqxx_expression integer(const T& t)
114 {
115 fmpqxx_expression res;
116 res.set_integer(t);
117 return res;
118 }
119
zero()120 static fmpqxx_expression zero(){return fmpqxx_expression();}
one()121 static fmpqxx_expression one()
122 {
123 fmpqxx_expression res;
124 res.set_one();
125 return res;
126 }
127
128 // These only make sense with immediates
canonicalise()129 void canonicalise() {fmpq_canonicalise(_fmpq());}
is_canonical()130 bool is_canonical() const {return fmpq_is_canonical(_fmpq());}
set_zero()131 void set_zero() {fmpq_zero(_fmpq());}
set_one()132 void set_one() {fmpq_one(_fmpq());}
133
134 template<class Vec>
set_cfrac(const Vec & v,slong n)135 void set_cfrac(const Vec& v, slong n)
136 {
137 fmpq_set_cfrac(this->_fmpq(), v._array(), n);
138 }
139
140 // Numerator and denominator access
141 typedef detail::fmpq_traits<fmpqxx_expression> traits_t;
num()142 typename traits_t::numreturn_t num() {return traits_t::num(*this);}
num()143 typename traits_t::cnumreturn_t num() const {return traits_t::num(*this);}
den()144 typename traits_t::denreturn_t den() {return traits_t::den(*this);}
den()145 typename traits_t::cdenreturn_t den() const
146 {return traits_t::den(*this);}
147
148 // These cause evaluation
is_zero()149 bool is_zero() const {return fmpq_is_zero(this->evaluate()._fmpq());}
is_one()150 bool is_one() const {return fmpq_is_one(this->evaluate()._fmpq());}
151 // TODO make this only work on immediates?
cfrac_bound()152 slong cfrac_bound() const {return fmpq_cfrac_bound(this->evaluate()._fmpq());}
sgn()153 int sgn() const {return fmpq_sgn(this->evaluate()._fmpq());}
height_bits()154 flint_bitcnt_t height_bits() const
155 {return fmpq_height_bits(this->evaluate()._fmpq());}
156
157 FLINTXX_DEFINE_MEMBER_UNOP_(next_minimal, fmpqxx_next_minimal)
158 FLINTXX_DEFINE_MEMBER_UNOP_(next_signed_minimal, fmpqxx_next_signed_minimal)
159 FLINTXX_DEFINE_MEMBER_UNOP_(next_calkin_wilf, fmpqxx_next_calkin_wilf)
160 FLINTXX_DEFINE_MEMBER_UNOP_(next_signed_calkin_wilf,
161 fmpqxx_next_signed_calkin_wilf)
162
163 // forwarded member functions
164 FLINTXX_DEFINE_MEMBER_UNOP(abs)
165 FLINTXX_DEFINE_MEMBER_UNOP(inv)
166 FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, height)
167 FLINTXX_DEFINE_MEMBER_BINOP(pow)
168 };
169
170 namespace detail {
171 struct fmpq_data;
172 }
173
174 typedef fmpqxx_expression<operations::immediate, detail::fmpq_data> fmpqxx;
175 typedef fmpqxx_expression<operations::immediate,
176 flint_classes::ref_data<fmpqxx, fmpq> > fmpqxx_ref;
177 typedef fmpqxx_expression<operations::immediate,
178 flint_classes::srcref_data<fmpqxx, fmpqxx_ref, fmpq> > fmpqxx_srcref;
179
180 namespace detail {
181 template<>
182 struct fmpq_traits<fmpqxx_srcref>
183 {
184 typedef fmpzxx_srcref numreturn_t;
185 typedef fmpzxx_srcref cnumreturn_t;
186 typedef fmpzxx_srcref denreturn_t;
187 typedef fmpzxx_srcref cdenreturn_t;
188 template<class T>
189 static cnumreturn_t num(T f)
190 {return cnumreturn_t::make(fmpq_numref(f._fmpq()));}
191 template<class T>
192 static cnumreturn_t den(T f)
193 {return cnumreturn_t::make(fmpq_denref(f._fmpq()));}
194 };
195 template<>
196 struct fmpq_traits<fmpqxx_ref>
197 {
198 typedef fmpzxx_ref numreturn_t;
199 typedef fmpzxx_ref denreturn_t;
200 typedef fmpzxx_ref cnumreturn_t;
201 typedef fmpzxx_ref cdenreturn_t;
202 template<class T>
203 static cnumreturn_t num(T f)
204 {return cnumreturn_t::make(fmpq_numref(f._fmpq()));}
205 template<class T>
206 static cnumreturn_t den(T f)
207 {return cnumreturn_t::make(fmpq_denref(f._fmpq()));}
208 };
209 template<> struct fmpq_traits<fmpqxx>
210 {
211 typedef fmpzxx_ref numreturn_t;
212 typedef fmpzxx_ref denreturn_t;
213 typedef fmpzxx_srcref cnumreturn_t;
214 typedef fmpzxx_srcref cdenreturn_t;
215 template<class T>
216 static cnumreturn_t num(const T& f)
217 {return cnumreturn_t::make(fmpq_numref(f._fmpq()));}
218 template<class T>
219 static cnumreturn_t den(const T& f)
220 {return cnumreturn_t::make(fmpq_denref(f._fmpq()));}
221 template<class T>
222 static numreturn_t num(T& f)
223 {return numreturn_t::make(fmpq_numref(f._fmpq()));}
224 template<class T>
225 static numreturn_t den(T& f)
226 {return numreturn_t::make(fmpq_denref(f._fmpq()));}
227 };
228
229 struct fmpq_data
230 {
231 fmpq_t inner;
232 typedef fmpq_t& data_ref_t;
233 typedef const fmpq_t& data_srcref_t;
234
235 fmpq_data() {fmpq_init(inner);}
236 ~fmpq_data() {fmpq_clear(inner);}
237
238 fmpq_data(const fmpq_data& o)
239 {
240 fmpq_init(inner);
241 fmpq_set(inner, o.inner);
242 }
243
244 fmpq_data(fmpqxx_srcref r)
245 {
246 fmpq_init(inner);
247 fmpq_set(inner, r._fmpq());
248 }
249
250 fmpq_data(fmpzxx_srcref num, fmpzxx_srcref den)
251 {
252 fmpq_init(inner);
253 fmpq_set_fmpz_frac(inner, num._fmpz(), den._fmpz());
254 }
255
256 template<class T, class U>
257 fmpq_data(T num, U den,
258 typename mp::enable_if<traits::fits_into_slong<T> >::type* = 0,
259 typename mp::enable_if<traits::is_unsigned_integer<U> >::type* = 0)
260 {
261 fmpq_init(inner);
262 fmpq_set_si(inner, num, den);
263 }
264 };
265 } // detail
266
267 // TODO macroize?
268 namespace traits {
269 template<class T> struct is_fmpqxx : mp::or_<
270 traits::is_T_expr<T, fmpqxx>,
271 flint_classes::is_source<fmpqxx, T> > { };
272 } // traits
273
274 namespace rules {
275 #define FMPQXX_COND_S FLINTXX_COND_S(fmpqxx)
276 #define FMPQXX_COND_T FLINTXX_COND_T(fmpqxx)
277
278 FLINT_DEFINE_DOIT_COND2(assignment, FMPQXX_COND_T, FMPQXX_COND_S,
279 fmpq_set(to._fmpq(), from._fmpq()))
280 FLINT_DEFINE_DOIT_COND2(assignment, FMPQXX_COND_T, traits::fits_into_slong,
281 fmpq_set_si(to._fmpq(), from, 1))
282 // TODO mpq, mpfr?
283
284 FLINTXX_DEFINE_TO_STR(fmpqxx, fmpq_get_str(0, base, from._fmpq()))
285
286 FLINTXX_DEFINE_CMP(fmpqxx, fmpq_cmp(e1._fmpq(), e2._fmpq()))
287
288 template<class T, class U>
289 struct cmp<T, U,
290 typename mp::enable_if<mp::and_<
291 FMPQXX_COND_S<T>, FMPZXX_COND_S<U> > >::type>
292 {
293 static int get(const T& v, const U& t)
294 {
295 return fmpq_cmp_fmpz(v._fmpq(), t._fmpz());
296 }
297 };
298
299 template<class T, class U>
300 struct cmp<T, U,
301 typename mp::enable_if<mp::and_<
302 FMPQXX_COND_S<T>, traits::is_unsigned_integer<U> > >::type>
303 {
304 static int get(const T& v, const U& t)
305 {
306 return fmpq_cmp_ui(v._fmpq(), t);
307 }
308 };
309
310 template<class T, class U>
311 struct cmp<T, U,
312 typename mp::enable_if<mp::and_<
313 FMPQXX_COND_S<T>, traits::is_signed_integer<U> > >::type>
314 {
315 static int get(const T& v, const U& t)
316 {
317 return fmpq_cmp_si(v._fmpq(), t);
318 }
319 };
320
321 FLINTXX_DEFINE_SWAP(fmpqxx, fmpq_swap(e1._fmpq(), e2._fmpq()))
322
323 FLINT_DEFINE_PRINT_COND(FMPQXX_COND_S, (fmpq_fprint(to, from._fmpq()), 1))
324
325 FLINT_DEFINE_GET_COND(conversion, double, FMPQXX_COND_S,
326 fmpq_get_d(from._fmpq()))
327
328 FLINT_DEFINE_CBINARY_EXPR_COND2(plus, fmpqxx, FMPQXX_COND_S, FMPQXX_COND_S,
329 fmpq_add(to._fmpq(), e1._fmpq(), e2._fmpq()))
330
331 FLINT_DEFINE_CBINARY_EXPR_COND2(plus, fmpqxx, FMPQXX_COND_S, FMPZXX_COND_S,
332 fmpq_add_fmpz(to._fmpq(), e1._fmpq(), e2._fmpz()))
333
334 FLINT_DEFINE_CBINARY_EXPR_COND2(plus, fmpqxx,
335 FMPQXX_COND_S, traits::is_unsigned_integer,
336 fmpq_add_ui(to._fmpq(), e1._fmpq(), e2))
337
338 FLINT_DEFINE_CBINARY_EXPR_COND2(plus, fmpqxx,
339 FMPQXX_COND_S, traits::is_signed_integer,
340 fmpq_add_si(to._fmpq(), e1._fmpq(), e2))
341
342 FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpqxx, FMPQXX_COND_S, FMPQXX_COND_S,
343 fmpq_sub(to._fmpq(), e1._fmpq(), e2._fmpq()))
344
345 FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpqxx, FMPQXX_COND_S, FMPZXX_COND_S,
346 fmpq_sub_fmpz(to._fmpq(), e1._fmpq(), e2._fmpz()))
347
348 FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpqxx,
349 FMPQXX_COND_S, traits::is_unsigned_integer,
350 fmpq_sub_ui(to._fmpq(), e1._fmpq(), e2))
351
352 FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpqxx,
353 FMPQXX_COND_S, traits::is_signed_integer,
354 fmpq_sub_si(to._fmpq(), e1._fmpq(), e2))
355
356 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpqxx, FMPQXX_COND_S, FMPQXX_COND_S,
357 fmpq_mul(to._fmpq(), e1._fmpq(), e2._fmpq()))
358
359 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpqxx, FMPQXX_COND_S, FMPZXX_COND_S,
360 fmpq_mul_fmpz(to._fmpq(), e1._fmpq(), e2._fmpz()))
361
362 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpqxx,
363 FMPQXX_COND_S, traits::is_unsigned_integer,
364 fmpq_mul_ui(to._fmpq(), e1._fmpq(), e2))
365
366 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpqxx,
367 FMPQXX_COND_S, traits::is_signed_integer,
368 fmpq_mul_si(to._fmpq(), e1._fmpq(), e2))
369
370 FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, fmpqxx, FMPQXX_COND_S,
371 FMPQXX_COND_S, fmpq_div(to._fmpq(), e1._fmpq(), e2._fmpq()))
372
373 FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, fmpqxx, FMPQXX_COND_S, FMPZXX_COND_S,
374 fmpq_div_fmpz(to._fmpq(), e1._fmpq(), e2._fmpz()))
375
376 FLINT_DEFINE_UNARY_EXPR_COND(negate, fmpqxx, FMPQXX_COND_S,
377 fmpq_neg(to._fmpq(), from._fmpq()))
378
379 FLINT_DEFINE_BINARY_EXPR_COND2(modulo, fmpzxx, FMPQXX_COND_S, FMPZXX_COND_S,
380 execution_check(fmpq_mod_fmpz(to._fmpz(), e1._fmpq(), e2._fmpz()),
381 "modular inversion", "fmpq"))
382
383 // TODO macroize?
384 namespace rdetail {
385 template<class Fmpq1, class Fmpq2, class T>
386 void fmpqxx_shift(Fmpq1& to, const Fmpq2& from, T howmuch)
387 {
388 if(howmuch < 0)
389 fmpq_div_2exp(to._fmpq(), from._fmpq(), -howmuch);
390 else
391 fmpq_mul_2exp(to._fmpq(), from._fmpq(), howmuch);
392 }
393 } // rdetail
394 FLINT_DEFINE_BINARY_EXPR_COND2(shift, fmpqxx,
395 FMPQXX_COND_S, traits::is_integer,
396 rdetail::fmpqxx_shift(to, e1, e2))
397 } // rules
398
399 FLINTXX_DEFINE_TERNARY(fmpqxx,
400 fmpq_addmul(to._fmpq(), e1._fmpq(), e2._fmpq()),
401 fmpq_submul(to._fmpq(), e1._fmpq(), e2._fmpq()),
402 FLINTXX_UNADORNED_MAKETYPES)
403
404 // immediate functions
405 template<class Fmpq>
406 inline typename mp::enable_if<traits::is_fmpqxx<Fmpq>, flint_bitcnt_t>::type
407 height_bits(const Fmpq& f)
408 {
409 return f.height_bits();
410 }
411
412 // TODO maybe as a member function?
413 template<class Fmpq1, class Fmpq2, class Vec>
414 inline typename mp::enable_if<mp::and_<
415 traits::is_fmpqxx<Fmpq2>,
416 FMPQXX_COND_T<Fmpq1> >,
417 int>::type
418 get_cfrac(Vec& v, Fmpq1& rem, const Fmpq2& x)
419 {
420 return fmpq_get_cfrac(v._array(), rem._fmpq(), x.evaluate()._fmpq(),
421 v.size());
422 }
423 // TODO also set_cfrac? c/f fmpqxx::set_cfrac ...
424
425 template<class Fmpq>
426 inline typename mp::enable_if<traits::is_fmpqxx<Fmpq>, int>::type
427 sgn(const Fmpq& f)
428 {
429 return f.sgn();
430 }
431
432 namespace rules {
433 FLINT_DEFINE_UNARY_EXPR_COND(abs_op, fmpqxx, FMPQXX_COND_S,
434 fmpq_abs(to._fmpq(), from._fmpq()))
435 FLINT_DEFINE_UNARY_EXPR_COND(height_op, fmpzxx, FMPQXX_COND_S,
436 fmpq_height(to._fmpz(), from._fmpq()))
437 FLINT_DEFINE_UNARY_EXPR_COND(inv_op, fmpqxx, FMPQXX_COND_S,
438 fmpq_inv(to._fmpq(), from._fmpq()))
439 FLINT_DEFINE_UNARY_EXPR_COND(fmpqxx_next_minimal_op, fmpqxx, FMPQXX_COND_S,
440 fmpq_next_minimal(to._fmpq(), from._fmpq()))
441 FLINT_DEFINE_UNARY_EXPR_COND(fmpqxx_next_signed_minimal_op, fmpqxx, FMPQXX_COND_S,
442 fmpq_next_signed_minimal(to._fmpq(), from._fmpq()))
443 FLINT_DEFINE_UNARY_EXPR_COND(fmpqxx_next_calkin_wilf_op, fmpqxx, FMPQXX_COND_S,
444 fmpq_next_calkin_wilf(to._fmpq(), from._fmpq()))
445 FLINT_DEFINE_UNARY_EXPR_COND(fmpqxx_next_signed_calkin_wilf_op, fmpqxx, FMPQXX_COND_S,
446 fmpq_next_signed_calkin_wilf(to._fmpq(), from._fmpq()))
447
448 FLINT_DEFINE_UNARY_EXPR_COND(fmpqxx_num_op, fmpzxx, FMPQXX_COND_S,
449 fmpz_set(to._fmpz(), fmpq_numref(from._fmpq())))
450 FLINT_DEFINE_UNARY_EXPR_COND(fmpqxx_den_op, fmpzxx, FMPQXX_COND_S,
451 fmpz_set(to._fmpz(), fmpq_denref(from._fmpq())))
452
453 // TODO should this throw a different exception type?
454 FLINT_DEFINE_BINARY_EXPR_COND2(fmpqxx_reconstruct_op, fmpqxx,
455 FMPZXX_COND_S, FMPZXX_COND_S,
456 execution_check(fmpq_reconstruct_fmpz(
457 to._fmpq(), e1._fmpz(), e2._fmpz()),
458 "rational reconstruction", "fmpq"))
459 FLINT_DEFINE_FOURARY_EXPR_COND4(fmpqxx_reconstruct_op, fmpqxx,
460 FMPZXX_COND_S, FMPZXX_COND_S, FMPZXX_COND_S, FMPZXX_COND_S,
461 execution_check(fmpq_reconstruct_fmpz_2(
462 to._fmpq(), e1._fmpz(), e2._fmpz(), e3._fmpz(), e4._fmpz()),
463 "rational reconstruction (v2)", "fmpq"))
464
465
466 FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, fmpqxx,
467 FMPQXX_COND_S, traits::fits_into_slong,
468 fmpq_pow_si(to._fmpq(), e1._fmpq(), e2))
469 }
470
471 } // flint
472
473 // fmpq_vecxx
474
475 #include "flintxx/vector.h"
476
477 namespace flint {
478 namespace detail {
479 struct fmpq_vector_data
480 {
481 slong size;
482 fmpq* array;
483
484 fmpq_vector_data(slong n)
485 : size(n), array(_fmpq_vec_init(n)) {}
486
487 ~fmpq_vector_data() {_fmpq_vec_clear(array, size);}
488
489 fmpq_vector_data(const fmpq_vector_data& o)
490 : size(o.size), array(_fmpq_vec_init(o.size))
491 {
492 for(slong i = 0;i < size;++i)
493 fmpq_set(array + i, o.array + i);
494 }
495
496 fmpqxx_ref at(slong i) {return fmpqxx_ref::make(array + i);}
497 fmpqxx_srcref at(slong i) const {return fmpqxx_srcref::make(array + i);}
498 };
499 } // detail
500
501 typedef vector_expression<
502 detail::wrapped_vector_traits<fmpqxx, slong, fmpqxx_ref, fmpqxx_srcref, fmpq>,
503 operations::immediate,
504 detail::fmpq_vector_data> fmpq_vecxx;
505
506 template<>
507 struct enable_vector_rules<fmpq_vecxx> : mp::false_ { };
508
509 namespace detail {
510 inline bool fmpq_vec_equal(const fmpq* v1, const fmpq* v2, slong n)
511 {
512 for(slong i = 0;i < n;++i)
513 if(!fmpq_equal(v1+i, v2+i))
514 return false;
515 return true;
516 }
517 }
518 namespace rules {
519 // TODO hack to make code look like references are implemented
520 template<class T> struct FMPQ_VECXX_COND_S : mp::equal_types<T, fmpq_vecxx> { };
521 #define FMPQ_VECXX_COND_T FMPQ_VECXX_COND_S
522
523 // TODO references
524 FLINT_DEFINE_GET(equals, bool, fmpq_vecxx,
525 e1.size() == e2.size()
526 && detail::fmpq_vec_equal(e1._data().array, e2._data().array, e1.size()))
527 } // rules
528 } // flint
529
530 #endif
531