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