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 FMPZ_POLY_MATXX_H
13 #define FMPZ_POLY_MATXX_H FMPZ_POLY_MATXX_H
14 
15 #include "fmpz_poly_mat.h"
16 
17 #include "fmpz_matxx.h"
18 #include "fmpz_polyxx.h"
19 #include "permxx.h"
20 
21 #include "flintxx/matrix.h"
22 
23 namespace flint {
FLINT_DEFINE_UNOP(prod)24 FLINT_DEFINE_UNOP(prod)
25 
26 namespace detail {
27 template<class Mat>
28 struct fmpz_poly_matxx_traits : matrices::generic_traits<Mat> { };
29 } // detail
30 
31 template<class Operation, class Data>
32 class fmpz_poly_matxx_expression
33     : public expression<derived_wrapper<fmpz_poly_matxx_expression>, Operation, Data>
34 {
35 public:
36     typedef expression<derived_wrapper< ::flint::fmpz_poly_matxx_expression>,
37               Operation, Data> base_t;
38     typedef detail::fmpz_poly_matxx_traits<fmpz_poly_matxx_expression> traits_t;
39 
40     FLINTXX_DEFINE_BASICS(fmpz_poly_matxx_expression)
FLINTXX_DEFINE_CTORS(fmpz_poly_matxx_expression)41     FLINTXX_DEFINE_CTORS(fmpz_poly_matxx_expression)
42     FLINTXX_DEFINE_C_REF(fmpz_poly_matxx_expression, fmpz_poly_mat_struct, _mat)
43 
44     template<class Expr>
45     static evaluated_t create_temporary_rowscols(
46             const Expr&, slong rows, slong cols)
47     {
48         return evaluated_t(rows, cols);
49     }
FLINTXX_DEFINE_MATRIX_METHODS(traits_t)50     FLINTXX_DEFINE_MATRIX_METHODS(traits_t)
51 
52     // static functions for fmpz_poly_matxx
53     template<class Fmpz_matxx>
54     static fmpz_poly_matxx_expression from_ground(const Fmpz_matxx& f)
55     {
56         return _from_ground(f.evaluate());
57     }
58     template<class Fmpz_matxx>
_from_ground(const Fmpz_matxx & f)59     static fmpz_poly_matxx_expression _from_ground(const Fmpz_matxx& f)
60     {
61         fmpz_poly_matxx_expression res(f.rows(), f.cols());
62         for(slong i = 0;i < f.rows();++i)
63             for(slong j = 0;j < f.rows();++j)
64                 res.at(i, j).set_coeff(0, f.at(i, j));
65         return res;
66     }
67 
randtest(slong rows,slong cols,frandxx & state,slong len,flint_bitcnt_t bits)68     static fmpz_poly_matxx_expression randtest(slong rows, slong cols,
69             frandxx& state, slong len, flint_bitcnt_t bits)
70     {
71         fmpz_poly_matxx_expression res(rows, cols);
72         res.set_randtest(state, len, bits);
73         return res;
74     }
randtest_unsigned(slong rows,slong cols,frandxx & state,slong len,flint_bitcnt_t bits)75     static fmpz_poly_matxx_expression randtest_unsigned(slong rows, slong cols,
76             frandxx& state, slong len, flint_bitcnt_t bits)
77     {
78         fmpz_poly_matxx_expression res(rows, cols);
79         res.set_randtest_unsigned(state, len, bits);
80         return res;
81     }
randtest_sparse(slong rows,slong cols,frandxx & state,slong len,flint_bitcnt_t bits,float density)82     static fmpz_poly_matxx_expression randtest_sparse(slong rows, slong cols,
83             frandxx& state, slong len, flint_bitcnt_t bits, float density)
84     {
85         fmpz_poly_matxx_expression res(rows, cols);
86         res.set_randtest_sparse(state, len, bits, density);
87         return res;
88     }
89 
zero(slong rows,slong cols)90     static fmpz_poly_matxx_expression zero(slong rows, slong cols)
91         {return fmpz_poly_matxx_expression(rows, cols);}
one(slong rows,slong cols)92     static fmpz_poly_matxx_expression one(slong rows, slong cols)
93     {
94         fmpz_poly_matxx_expression res(rows, cols);
95         res.set_one();
96         return res;
97     }
98 
99     // these only make sense with targets
set_randtest(frandxx & state,slong len,flint_bitcnt_t bits)100     void set_randtest(frandxx& state, slong len, flint_bitcnt_t bits)
101         {fmpz_poly_mat_randtest(_mat(), state._data(), len, bits);}
set_randtest_unsigned(frandxx & state,slong len,flint_bitcnt_t bits)102     void set_randtest_unsigned(frandxx& state, slong len, flint_bitcnt_t bits)
103         {fmpz_poly_mat_randtest_unsigned(_mat(), state._data(), len, bits);}
set_randtest_sparse(frandxx & state,slong len,flint_bitcnt_t bits,float density)104     void set_randtest_sparse(frandxx& state, slong len, flint_bitcnt_t bits,
105             float density)
106         {fmpz_poly_mat_randtest_sparse(_mat(), state._data(), len, bits, density);}
truncate(slong len)107     void truncate(slong len) {fmpz_poly_mat_truncate(_mat(), len);}
set_zero()108     void set_zero()
109         {fmpz_poly_mat_zero(_mat());}
set_one()110     void set_one()
111         {fmpz_poly_mat_one(_mat());}
112 
113     // these cause evaluation
rank()114     slong rank() const {return fmpz_poly_mat_rank(this->evaluate()._mat());}
is_zero()115     bool is_zero() const
116         {return fmpz_poly_mat_is_zero(this->evaluate()._mat());}
is_one()117     bool is_one() const
118         {return fmpz_poly_mat_is_one(this->evaluate()._mat());}
is_empty()119     bool is_empty() const
120         {return fmpz_poly_mat_is_empty(this->evaluate()._mat());}
is_square()121     bool is_square() const
122         {return fmpz_poly_mat_is_square(this->evaluate()._mat());}
max_length()123     slong max_length() const
124         {return fmpz_poly_mat_max_length(this->evaluate()._mat());}
max_bits()125     slong max_bits() const
126         {return fmpz_poly_mat_max_bits(this->evaluate()._mat());}
find_pivot_any(slong start,slong end,slong c)127     slong find_pivot_any(slong start, slong end, slong c) const
128     {
129         return fmpz_poly_mat_find_pivot_any(
130                 this->evaluate()._mat(), start, end, c);
131     }
find_pivot_partial(slong start,slong end,slong c)132     slong find_pivot_partial(slong start, slong end, slong c) const
133     {
134         return fmpz_poly_mat_find_pivot_partial(
135                 this->evaluate()._mat(), start, end, c);
136     }
137 
138     // forwarded lazy ops
139     FLINTXX_DEFINE_MEMBER_BINOP_(operator(), compeval)
140 
141     FLINTXX_DEFINE_MEMBER_3OP(mullow)
142     FLINTXX_DEFINE_MEMBER_3OP(pow_trunc)
143 
144     FLINTXX_DEFINE_MEMBER_BINOP(solve)
145     FLINTXX_DEFINE_MEMBER_BINOP(solve_fflu)
146     FLINTXX_DEFINE_MEMBER_BINOP(mul_KS)
147     FLINTXX_DEFINE_MEMBER_BINOP(mul_classical)
148     FLINTXX_DEFINE_MEMBER_BINOP(pow)
149     FLINTXX_DEFINE_MEMBER_BINOP(sqrlow)
150 
151     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpz_polyxx, det)
152     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpz_polyxx, det_fflu)
153     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpz_polyxx, det_interpolate)
154     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpz_polyxx, trace)
155     FLINTXX_DEFINE_MEMBER_UNOP(sqr)
156     FLINTXX_DEFINE_MEMBER_UNOP(sqr_classical)
157     FLINTXX_DEFINE_MEMBER_UNOP(sqr_KS)
158     FLINTXX_DEFINE_MEMBER_UNOP(transpose)
159 
160     //FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(nullspace) // TODO
161     //FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(???, inv) // TODO
162     //FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(???, rref) // TODO
163 
164     FLINTXX_DEFINE_MEMBER_FFLU
165 };
166 
167 namespace detail {
168 struct fmpz_poly_mat_data;
169 } // detail
170 
171 typedef fmpz_poly_matxx_expression<operations::immediate,
172             detail::fmpz_poly_mat_data> fmpz_poly_matxx;
173 typedef fmpz_poly_matxx_expression<operations::immediate,
174             flint_classes::ref_data<fmpz_poly_matxx,
175             fmpz_poly_mat_struct> > fmpz_poly_matxx_ref;
176 typedef fmpz_poly_matxx_expression<operations::immediate,
177             flint_classes::srcref_data<
178                 fmpz_poly_matxx, fmpz_poly_matxx_ref,
179                 fmpz_poly_mat_struct> > fmpz_poly_matxx_srcref;
180 
181 template<>
182 struct matrix_traits<fmpz_poly_matxx>
183 {
184     template<class M> static slong rows(const M& m)
185     {
186         return fmpz_poly_mat_nrows(m._mat());
187     }
188     template<class M> static slong cols(const M& m)
189     {
190         return fmpz_poly_mat_ncols(m._mat());
191     }
192 
193     template<class M> static fmpz_polyxx_srcref at(const M& m, slong i, slong j)
194     {
195         return fmpz_polyxx_srcref::make(fmpz_poly_mat_entry(m._mat(), i, j));
196     }
197     template<class M> static fmpz_polyxx_ref at(M& m, slong i, slong j)
198     {
199         return fmpz_polyxx_ref::make(fmpz_poly_mat_entry(m._mat(), i, j));
200     }
201 };
202 
203 namespace detail {
204 template<>
205 struct fmpz_poly_matxx_traits<fmpz_poly_matxx_srcref>
206     : matrices::generic_traits_srcref<fmpz_polyxx_srcref> { };
207 template<>
208 struct fmpz_poly_matxx_traits<fmpz_poly_matxx_ref>
209     : matrices::generic_traits_ref<fmpz_polyxx_ref> { };
210 template<> struct fmpz_poly_matxx_traits<fmpz_poly_matxx>
211     : matrices::generic_traits_nonref<fmpz_polyxx_ref, fmpz_polyxx_srcref> { };
212 
213 struct fmpz_poly_mat_data
214 {
215     typedef fmpz_poly_mat_t& data_ref_t;
216     typedef const fmpz_poly_mat_t& data_srcref_t;
217 
218     fmpz_poly_mat_t inner;
219 
220     fmpz_poly_mat_data(slong m, slong n)
221     {
222         fmpz_poly_mat_init(inner, m, n);
223     }
224 
225     fmpz_poly_mat_data(const fmpz_poly_mat_data& o)
226     {
227         fmpz_poly_mat_init_set(inner, o.inner);
228     }
229 
230     fmpz_poly_mat_data(fmpz_poly_matxx_srcref o)
231     {
232         fmpz_poly_mat_init_set(inner, o._data().inner);
233     }
234 
235     ~fmpz_poly_mat_data() {fmpz_poly_mat_clear(inner);}
236 };
237 } // detail
238 
239 #define FMPZ_POLY_MATXX_COND_S FLINTXX_COND_S(fmpz_poly_matxx)
240 #define FMPZ_POLY_MATXX_COND_T FLINTXX_COND_T(fmpz_poly_matxx)
241 
242 namespace matrices {
243 template<>
244 struct outsize<operations::mul_KS_op>
245     : outsize<operations::times> { };
246 template<>
247 struct outsize<operations::mullow_op>
248     : outsize<operations::times> { };
249 } // matrices
250 
251 FLINTXX_DEFINE_TEMPORARY_RULES(fmpz_poly_matxx)
252 
253 namespace rules {
254 FLINT_DEFINE_DOIT_COND2(assignment, FMPZ_POLY_MATXX_COND_T, FMPZ_POLY_MATXX_COND_S,
255         fmpz_poly_mat_set(to._mat(), from._mat()))
256 
257 FLINTXX_DEFINE_SWAP(fmpz_poly_matxx, fmpz_poly_mat_swap(e1._mat(), e2._mat()))
258 
259 FLINTXX_DEFINE_EQUALS(fmpz_poly_matxx, fmpz_poly_mat_equal(e1._mat(), e2._mat()))
260 
261 FLINT_DEFINE_PRINT_PRETTY_COND_2(FMPZ_POLY_MATXX_COND_S, const char*,
262         (fmpz_poly_mat_print(from._mat(), extra), 1))
263 
264 FLINT_DEFINE_BINARY_EXPR_COND2(times, fmpz_poly_matxx,
265         FMPZ_POLY_MATXX_COND_S, FMPZ_POLY_MATXX_COND_S,
266         fmpz_poly_mat_mul(to._mat(), e1._mat(), e2._mat()))
267 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpz_poly_matxx,
268         FMPZ_POLY_MATXX_COND_S, FMPZXX_COND_S,
269         fmpz_poly_mat_scalar_mul_fmpz(to._mat(), e1._mat(), e2._fmpz()))
270 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpz_poly_matxx,
271         FMPZ_POLY_MATXX_COND_S, FMPZ_POLYXX_COND_S,
272         fmpz_poly_mat_scalar_mul_fmpz_poly(to._mat(), e1._mat(), e2._poly()))
273 
274 FLINT_DEFINE_BINARY_EXPR_COND2(plus, fmpz_poly_matxx,
275         FMPZ_POLY_MATXX_COND_S, FMPZ_POLY_MATXX_COND_S,
276         fmpz_poly_mat_add(to._mat(), e1._mat(), e2._mat()))
277 FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpz_poly_matxx,
278         FMPZ_POLY_MATXX_COND_S, FMPZ_POLY_MATXX_COND_S,
279         fmpz_poly_mat_sub(to._mat(), e1._mat(), e2._mat()))
280 
281 FLINT_DEFINE_UNARY_EXPR_COND(negate, fmpz_poly_matxx, FMPZ_POLY_MATXX_COND_S,
282         fmpz_poly_mat_neg(to._mat(), from._mat()))
283 
284 FLINT_DEFINE_UNARY_EXPR_COND(transpose_op, fmpz_poly_matxx, FMPZ_POLY_MATXX_COND_S,
285         fmpz_poly_mat_transpose(to._mat(), from._mat()))
286 FLINT_DEFINE_UNARY_EXPR_COND(trace_op, fmpz_polyxx, FMPZ_POLY_MATXX_COND_S,
287         fmpz_poly_mat_trace(to._poly(), from._mat()))
288 
289 FLINT_DEFINE_THREEARY_EXPR_COND3(mat_at_op, fmpz_polyxx,
290         FMPZ_POLY_MATXX_COND_S, traits::fits_into_slong, traits::fits_into_slong,
291         fmpz_poly_set(to._poly(), fmpz_poly_mat_entry(e1._mat(), e2, e3)))
292 
293 FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_op, fmpz_matxx,
294         FMPZ_POLY_MATXX_COND_S, FMPZXX_COND_S,
295         fmpz_poly_mat_evaluate_fmpz(to._mat(), e1._mat(), e2._fmpz()))
296 
297 FLINT_DEFINE_BINARY_EXPR_COND2(mul_classical_op, fmpz_poly_matxx,
298         FMPZ_POLY_MATXX_COND_S, FMPZ_POLY_MATXX_COND_S,
299         fmpz_poly_mat_mul_classical(to._mat(), e1._mat(), e2._mat()))
300 FLINT_DEFINE_BINARY_EXPR_COND2(mul_KS_op, fmpz_poly_matxx,
301         FMPZ_POLY_MATXX_COND_S, FMPZ_POLY_MATXX_COND_S,
302         fmpz_poly_mat_mul_KS(to._mat(), e1._mat(), e2._mat()))
303 
304 FLINT_DEFINE_THREEARY_EXPR_COND3(mullow_op, fmpz_poly_matxx,
305     FMPZ_POLY_MATXX_COND_S, FMPZ_POLY_MATXX_COND_S, traits::fits_into_slong,
306     fmpz_poly_mat_mullow(to._mat(), e1._mat(), e2._mat(), e3))
307 
308 FLINT_DEFINE_UNARY_EXPR_COND(sqr_op, fmpz_poly_matxx, FMPZ_POLY_MATXX_COND_S,
309         fmpz_poly_mat_sqr(to._mat(), from._mat()))
310 FLINT_DEFINE_UNARY_EXPR_COND(sqr_classical_op, fmpz_poly_matxx,
311         FMPZ_POLY_MATXX_COND_S,
312         fmpz_poly_mat_sqr_classical(to._mat(), from._mat()))
313 FLINT_DEFINE_UNARY_EXPR_COND(sqr_KS_op, fmpz_poly_matxx,
314         FMPZ_POLY_MATXX_COND_S,
315         fmpz_poly_mat_sqr_KS(to._mat(), from._mat()))
316 FLINT_DEFINE_BINARY_EXPR_COND2(sqrlow_op, fmpz_poly_matxx,
317         FMPZ_POLY_MATXX_COND_S, traits::fits_into_slong,
318         fmpz_poly_mat_sqrlow(to._mat(), e1._mat(), e2))
319 
320 FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, fmpz_poly_matxx,
321         FMPZ_POLY_MATXX_COND_S, traits::is_unsigned_integer,
322         fmpz_poly_mat_pow(to._mat(), e1._mat(), e2))
323 
324 FLINT_DEFINE_THREEARY_EXPR_COND3(pow_trunc_op, fmpz_poly_matxx,
325     FMPZ_POLY_MATXX_COND_S, traits::is_unsigned_integer, traits::fits_into_slong,
326     fmpz_poly_mat_pow_trunc(to._mat(), e1._mat(), e2, e3))
327 
328 FLINT_DEFINE_UNARY_EXPR_COND(det_op, fmpz_polyxx, FMPZ_POLY_MATXX_COND_S,
329         fmpz_poly_mat_det(to._poly(), from._mat()))
330 FLINT_DEFINE_UNARY_EXPR_COND(det_fflu_op, fmpz_polyxx, FMPZ_POLY_MATXX_COND_S,
331         fmpz_poly_mat_det_fflu(to._poly(), from._mat()))
332 FLINT_DEFINE_UNARY_EXPR_COND(det_interpolate_op, fmpz_polyxx,
333         FMPZ_POLY_MATXX_COND_S,
334         fmpz_poly_mat_det_interpolate(to._poly(), from._mat()))
335 
336 namespace rdetail {
337 typedef make_ltuple<mp::make_tuple<bool, fmpz_poly_matxx, fmpz_polyxx>::type >::type
338     fmpz_poly_mat_inv_rt;
339 
340 typedef make_ltuple<mp::make_tuple<slong, fmpz_poly_matxx>::type >::type
341     fmpz_poly_mat_nullspace_rt;
342 }
343 FLINT_DEFINE_UNARY_EXPR_COND(inv_op, rdetail::fmpz_poly_mat_inv_rt,
344         FMPZ_POLY_MATXX_COND_S,
345         to.template get<0>() = fmpz_poly_mat_inv(to.template get<1>()._mat(),
346             to.template get<2>()._poly(), from._mat()))
347 FLINT_DEFINE_UNARY_EXPR_COND(nullspace_op, rdetail::fmpz_poly_mat_nullspace_rt,
348         FMPZ_POLY_MATXX_COND_S, to.template get<0>() = fmpz_poly_mat_nullspace(
349             to.template get<1>()._mat(), from._mat()))
350 
351 FLINT_DEFINE_BINARY_EXPR_COND2(solve_op, rdetail::fmpz_poly_mat_inv_rt,
352         FMPZ_POLY_MATXX_COND_S, FMPZ_POLY_MATXX_COND_S,
353         to.template get<0>() = fmpz_poly_mat_solve(to.template get<1>()._mat(),
354             to.template get<2>()._poly(), e1._mat(), e2._mat()))
355 FLINT_DEFINE_BINARY_EXPR_COND2(solve_fflu_op, rdetail::fmpz_poly_mat_inv_rt,
356         FMPZ_POLY_MATXX_COND_S, FMPZ_POLY_MATXX_COND_S,
357         to.template get<0>() = fmpz_poly_mat_solve_fflu(
358             to.template get<1>()._mat(),
359             to.template get<2>()._poly(), e1._mat(), e2._mat()))
360 
361 namespace rdetail {
362 typedef make_ltuple<mp::make_tuple<slong, fmpz_poly_matxx, fmpz_polyxx>::type>::type
363     fmpz_poly_matxx_fflu_rt;
364 } // rdetail
365 
366 FLINT_DEFINE_THREEARY_EXPR_COND3(fflu_op, rdetail::fmpz_poly_matxx_fflu_rt,
367         FMPZ_POLY_MATXX_COND_S, traits::is_maybe_perm, tools::is_bool,
368         to.template get<0>() = fmpz_poly_mat_fflu(to.template get<1>()._mat(),
369             to.template get<2>()._poly(), maybe_perm_data(e2), e1._mat(), e3))
370 
371 FLINT_DEFINE_UNARY_EXPR_COND(rref_op, rdetail::fmpz_poly_matxx_fflu_rt,
372         FMPZ_POLY_MATXX_COND_S,
373         to.template get<0>() = fmpz_poly_mat_rref(to.template get<1>()._mat(),
374             to.template get<2>()._poly(), from._mat()))
375 
376 FLINT_DEFINE_THREEARY_EXPR_COND3(solve_fflu_precomp_op, fmpz_poly_matxx,
377         traits::is_permxx, FMPZ_POLY_MATXX_COND_S, FMPZ_POLY_MATXX_COND_S,
378         fmpz_poly_mat_solve_fflu_precomp(to._mat(), e1._data(),
379             e2._mat(), e3._mat()))
380 } // rules
381 
382 
383 ////////////////////////////////////////////////////////////////////////////
384 // fmpz_poly_mat_vecxx and prod
385 ////////////////////////////////////////////////////////////////////////////
386 namespace detail {
387 struct fmpz_poly_mat_vector_data
388 {
389     slong size;
390     fmpz_poly_mat_t* array;
391 
392     fmpz_poly_mat_vector_data(slong n, slong rows, slong cols)
393         : size(n)
394     {
395         array = new fmpz_poly_mat_t[n];
396         for(slong i = 0; i < n; ++i)
397             fmpz_poly_mat_init(array[i], rows, cols);
398     }
399 
400     ~fmpz_poly_mat_vector_data()
401     {
402         for(slong i = 0; i < size; ++i)
403             fmpz_poly_mat_clear(array[i]);
404         delete[] array;
405     }
406 
407     fmpz_poly_mat_vector_data(const fmpz_poly_mat_vector_data& o)
408         : size(o.size)
409     {
410         array = new fmpz_poly_mat_t[size];
411         for(slong i = 0; i < size; ++i)
412             fmpz_poly_mat_init_set(array[i], o.array[i]);
413     }
414 
415     fmpz_poly_matxx_ref at(slong i)
416         {return fmpz_poly_matxx_ref::make(array[i]);}
417     fmpz_poly_matxx_srcref at(slong i) const
418         {return fmpz_poly_matxx_srcref::make(array[i]);}
419 
420     bool equals(const fmpz_poly_mat_vector_data& o) const
421     {
422         if(size != o.size)
423             return false;
424         for(slong i = 0; i < size; ++i)
425             if(!fmpz_poly_mat_equal(array[i], o.array[i]))
426                 return false;
427         return true;
428     }
429 };
430 } // detail
431 // TODO temporary allocation
432 
433 typedef vector_expression<
434     detail::wrapped_vector_traits<fmpz_poly_matxx, slong,
435         fmpz_poly_matxx_ref, fmpz_poly_matxx_srcref, fmpz_poly_mat_t>,
436     operations::immediate,
437     detail::fmpz_poly_mat_vector_data> fmpz_poly_mat_vecxx;
438 // TODO references
439 
440 template<>
441 struct enable_vector_rules<fmpz_poly_mat_vecxx> : mp::false_ { };
442 
443 namespace matrices {
444 template<>
445 struct outsize<operations::prod_op>
446 {
447     template<class Mat>
448     static slong rows(const Mat& m)
449     {
450         return m._data().head[0].rows();
451     }
452     template<class Mat>
453     static slong cols(const Mat& m)
454     {
455         return m._data().head[0].cols();
456     }
457 };
458 }
459 
460 namespace rules {
461 // TODO hack to make code look like references are implemented
462 template<class T> struct FMPZ_POLY_MAT_VECXX_COND_S
463     : mp::equal_types<T, fmpz_poly_mat_vecxx> { };
464 #define FMPZ_POLY_MAT_VECXX_COND_T FMPZ_POLY_MAT_VECXX_COND_S
465 
466 // TODO references
467 FLINT_DEFINE_GET(equals, bool, fmpz_poly_mat_vecxx, e1._data().equals(e2._data()))
468 
469 FLINT_DEFINE_UNARY_EXPR_COND(prod_op, fmpz_poly_matxx,
470         FMPZ_POLY_MAT_VECXX_COND_S,
471         fmpz_poly_mat_prod(to._mat(), (fmpz_poly_mat_t * const) from._array(), from.size()))
472 } // rules
473 
474 } // flint
475 
476 #endif
477