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_MATXX_H
13 #define FMPZ_MATXX_H FMPZ_MATXX_H
14 
15 #include "fmpz_mat.h"
16 #include "fmpq_mat.h" // fmpq_mat_get_fmpz_mat_mod_fmpz
17 
18 #include "fmpzxx.h"
19 #include "fmpz_polyxx.h"
20 #include "permxx.h"
21 
22 #include "flintxx/ltuple.h"
23 #include "flintxx/matrix.h"
24 #include "flintxx/traits_fwd.h"
25 
26 // TODO input and output
27 // TODO addmul
28 // TODO nullspace member
29 
30 namespace flint {
31 FLINT_DEFINE_BINOP(det_modular)
FLINT_DEFINE_BINOP(det_modular_accelerated)32 FLINT_DEFINE_BINOP(det_modular_accelerated)
33 FLINT_DEFINE_BINOP(mul_multi_mod)
34 FLINT_DEFINE_BINOP(solve_dixon)
35 FLINT_DEFINE_BINOP(solve_cramer)
36 FLINT_DEFINE_BINOP(solve_bound)
37 FLINT_DEFINE_THREEARY(det_modular_given_divisor)
38 FLINT_DEFINE_UNOP(det_bareiss)
39 FLINT_DEFINE_UNOP(det_bound)
40 FLINT_DEFINE_UNOP(det_cofactor)
41 FLINT_DEFINE_UNOP(det_divisor)
42 
43 namespace detail {
44 template<class Mat>
45 struct fmpz_matxx_traits : matrices::generic_traits<Mat> { };
46 } // detail
47 
48 template<class Operation, class Data>
49 class fmpz_matxx_expression
50     : public expression<derived_wrapper<fmpz_matxx_expression>, Operation, Data>
51 {
52 public:
53     typedef expression<derived_wrapper< ::flint::fmpz_matxx_expression>,
54               Operation, Data> base_t;
55     typedef detail::fmpz_matxx_traits<fmpz_matxx_expression> traits_t;
56 
57     FLINTXX_DEFINE_BASICS(fmpz_matxx_expression)
FLINTXX_DEFINE_CTORS(fmpz_matxx_expression)58     FLINTXX_DEFINE_CTORS(fmpz_matxx_expression)
59     FLINTXX_DEFINE_C_REF(fmpz_matxx_expression, fmpz_mat_struct, _mat)
60 
61     template<class Expr>
62     static evaluated_t create_temporary_rowscols(
63             const Expr&, slong rows, slong cols)
64     {
65         return evaluated_t(rows, cols);
66     }
FLINTXX_DEFINE_MATRIX_METHODS(traits_t)67     FLINTXX_DEFINE_MATRIX_METHODS(traits_t)
68 
69     template<class Nmod_mat>
70     static fmpz_matxx_expression lift(const Nmod_mat& mat,
71             typename mp::enable_if<traits::is_nmod_matxx<Nmod_mat> >::type* = 0)
72     {
73         fmpz_matxx_expression res(mat.rows(), mat.cols());
74         fmpz_mat_set_nmod_mat(res._mat(), mat.evaluate()._mat());
75         return res;
76     }
77     template<class Nmod_mat>
78     static fmpz_matxx_expression lift_unsigned(const Nmod_mat& mat,
79             typename mp::enable_if<traits::is_nmod_matxx<Nmod_mat> >::type* = 0)
80     {
81         fmpz_matxx_expression res(mat.rows(), mat.cols());
82         fmpz_mat_set_nmod_mat_unsigned(res._mat(), mat.evaluate()._mat());
83         return res;
84     }
85 
86     template<class Fmpq_mat, class Fmpz>
87     static fmpz_matxx_expression reduce(const Fmpq_mat& mat, const Fmpz& mod,
88             typename mp::enable_if<traits::is_fmpq_matxx<Fmpq_mat> >::type* = 0,
89             typename mp::enable_if<traits::is_fmpzxx<Fmpz> >::type* = 0)
90     {
91         fmpz_matxx_expression res(mat.rows(), mat.cols());
92         fmpq_mat_get_fmpz_mat_mod_fmpz(res._mat(), mat.evaluate()._mat(),
93                 mod.evaluate()._fmpz());
94         return res;
95     }
96 
97     template<class Fmpq_mat>
98     static fmpz_matxx_expression from_integral_fraction(const Fmpq_mat& mat,
99             typename mp::enable_if<traits::is_fmpq_matxx<Fmpq_mat> >::type* = 0)
100     {
101         fmpz_matxx_expression res(mat.rows(), mat.cols());
102         res.set_integral_fraction(mat);
103         return res;
104     }
105     template<class Fmpq_mat>
106     void set_integral_fraction(const Fmpq_mat& mat,
107             typename mp::enable_if<traits::is_fmpq_matxx<Fmpq_mat> >::type* = 0)
108     {
109         execution_check(fmpq_mat_get_fmpz_mat(_mat(), mat.evaluate()._mat()),
110                 "set_integral_fraction", "fmpq_matxx");
111     }
112 
randbits(slong rows,slong cols,frandxx & state,flint_bitcnt_t bits)113     static fmpz_matxx_expression randbits(slong rows, slong cols,
114             frandxx& state, flint_bitcnt_t bits)
115     {
116         fmpz_matxx_expression res(rows, cols);
117         res.set_randbits(state, bits);
118         return res;
119     }
randtest(slong rows,slong cols,frandxx & state,flint_bitcnt_t bits)120     static fmpz_matxx_expression randtest(slong rows, slong cols,
121             frandxx& state, flint_bitcnt_t bits)
122     {
123         fmpz_matxx_expression res(rows, cols);
124         res.set_randtest(state, bits);
125         return res;
126     }
randintrel(slong rows,slong cols,frandxx & state,flint_bitcnt_t bits)127     static fmpz_matxx_expression randintrel(slong rows, slong cols,
128             frandxx& state, flint_bitcnt_t bits)
129     {
130         fmpz_matxx_expression res(rows, cols);
131         res.set_randintrel(state, bits);
132         return res;
133     }
randsimdioph(slong rows,slong cols,frandxx & state,flint_bitcnt_t bits,flint_bitcnt_t bits2)134     static fmpz_matxx_expression randsimdioph(slong rows, slong cols,
135             frandxx& state, flint_bitcnt_t bits, flint_bitcnt_t bits2)
136     {
137         fmpz_matxx_expression res(rows, cols);
138         res.set_randsimdioph(state, bits, bits2);
139         return res;
140     }
randntrulike(slong rows,slong cols,frandxx & state,flint_bitcnt_t bits,ulong q)141     static fmpz_matxx_expression randntrulike(slong rows, slong cols,
142             frandxx& state, flint_bitcnt_t bits, ulong q)
143     {
144         fmpz_matxx_expression res(rows, cols);
145         res.set_randntrulike(state, bits, q);
146         return res;
147     }
randntrulike2(slong rows,slong cols,frandxx & state,flint_bitcnt_t bits,ulong q)148     static fmpz_matxx_expression randntrulike2(slong rows, slong cols,
149             frandxx& state, flint_bitcnt_t bits, ulong q)
150     {
151         fmpz_matxx_expression res(rows, cols);
152         res.set_randntrulike2(state, bits, q);
153         return res;
154     }
randajtai(slong rows,slong cols,frandxx & state,flint_bitcnt_t bits,double alpha)155     static fmpz_matxx_expression randajtai(slong rows, slong cols,
156             frandxx& state, flint_bitcnt_t bits, double alpha)
157     {
158         fmpz_matxx_expression res(rows, cols);
159         res.set_randajtai(state, bits, alpha);
160         return res;
161     }
randrank(slong rows,slong cols,frandxx & state,slong rank,flint_bitcnt_t bits)162     static fmpz_matxx_expression randrank(slong rows, slong cols,
163             frandxx& state, slong rank, flint_bitcnt_t bits)
164     {
165         fmpz_matxx_expression res(rows, cols);
166         res.set_randrank(state, rank, bits);
167         return res;
168     }
169     template<class Fmpz>
170     static typename mp::enable_if<traits::is_fmpzxx<Fmpz>,
171                         fmpz_matxx_expression>::type
randdet(slong rows,slong cols,frandxx & state,const Fmpz & d)172     randdet(slong rows, slong cols, frandxx& state, const Fmpz& d)
173     {
174         fmpz_matxx_expression res(rows, cols);
175         res.set_randdet(state, d);
176         return res;
177     }
178 
zero(slong rows,slong cols)179     static fmpz_matxx_expression zero(slong rows, slong cols)
180         {return fmpz_matxx_expression(rows, cols);}
one(slong rows,slong cols)181     static fmpz_matxx_expression one(slong rows, slong cols)
182     {
183         fmpz_matxx_expression res(rows, cols);
184         res.set_one();
185         return res;
186     }
187 
188     // these only make sense with targets
set_randbits(frandxx & state,flint_bitcnt_t bits)189     void set_randbits(frandxx& state, flint_bitcnt_t bits)
190         {fmpz_mat_randbits(_mat(), state._data(), bits);}
set_randtest(frandxx & state,flint_bitcnt_t bits)191     void set_randtest(frandxx& state, flint_bitcnt_t bits)
192         {fmpz_mat_randtest(_mat(), state._data(), bits);}
set_randintrel(frandxx & state,flint_bitcnt_t bits)193     void set_randintrel(frandxx& state, flint_bitcnt_t bits)
194         {fmpz_mat_randintrel(_mat(), state._data(), bits);}
set_randsimdioph(frandxx & state,flint_bitcnt_t bits,flint_bitcnt_t bits2)195     void set_randsimdioph(frandxx& state, flint_bitcnt_t bits, flint_bitcnt_t bits2)
196         {fmpz_mat_randsimdioph(_mat(), state._data(), bits, bits2);}
set_randntrulike(frandxx & state,flint_bitcnt_t bits,ulong q)197     void set_randntrulike(frandxx& state, flint_bitcnt_t bits, ulong q)
198         {fmpz_mat_randntrulike(_mat(), state._data(), bits, q);}
set_randntrulike2(frandxx & state,flint_bitcnt_t bits,ulong q)199     void set_randntrulike2(frandxx& state, flint_bitcnt_t bits, ulong q)
200         {fmpz_mat_randntrulike2(_mat(), state._data(), bits, q);}
set_randajtai(frandxx & state,flint_bitcnt_t bits,double alpha)201     void set_randajtai(frandxx& state, flint_bitcnt_t bits, double alpha)
202         {fmpz_mat_randajtai(_mat(), state._data(), bits, alpha);}
set_randrank(frandxx & state,slong rank,flint_bitcnt_t bits)203     void set_randrank(frandxx& state, slong rank, flint_bitcnt_t bits)
204         {fmpz_mat_randrank(_mat(), state._data(), rank, bits);}
205 
206     template<class Fmpz>
207     typename mp::enable_if<traits::is_fmpzxx<Fmpz> >::type
set_randdet(frandxx & state,const Fmpz & d)208     set_randdet(frandxx& state, const Fmpz& d)
209         {fmpz_mat_randdet(_mat(), state._data(), d.evaluate()._fmpz());}
210 
211     template<class Vec>
set_randpermdiag(frandxx & state,const Vec & v)212     int set_randpermdiag(frandxx& state, const Vec& v)
213     {
214         return fmpz_mat_randpermdiag(_mat(), state._data(), v._array(), v.size());
215     }
216 
apply_randops(frandxx & state,slong count)217     void apply_randops(frandxx& state, slong count)
218         {fmpz_mat_randops(_mat(), state._data(), count);}
219 
set_zero()220     void set_zero()
221         {fmpz_mat_zero(_mat());}
set_one()222     void set_one()
223         {fmpz_mat_one(_mat());}
224 
225     template<class Fmpz>
226     slong set_rref_mod(const Fmpz& p, permxx* perm = 0,
227             typename mp::enable_if<traits::is_fmpzxx<Fmpz> >::type* = 0)
228     {
229         return fmpz_mat_rref_mod(maybe_perm_data(perm), _mat(), p.evaluate()._fmpz());
230     }
231 
232     // these cause evaluation
rank()233     slong rank() const {return fmpz_mat_rank(this->evaluate()._mat());}
is_zero()234     bool is_zero() const {return fmpz_mat_is_zero(this->evaluate()._mat());}
is_empty()235     bool is_empty() const {return fmpz_mat_is_empty(this->evaluate()._mat());}
is_square()236     bool is_square() const {return fmpz_mat_is_square(this->evaluate()._mat());}
find_pivot_any(slong start,slong end,slong c)237     slong find_pivot_any(slong start, slong end, slong c) const
238         {return fmpz_mat_find_pivot_any(this->evaluate()._mat(), start, end, c);}
239 
240     // forwarded lazy ops
241     FLINTXX_DEFINE_MEMBER_BINOP(det_modular)
242     FLINTXX_DEFINE_MEMBER_BINOP(det_modular_accelerated)
243     FLINTXX_DEFINE_MEMBER_BINOP(divexact)
244     FLINTXX_DEFINE_MEMBER_BINOP(mul_classical)
245     FLINTXX_DEFINE_MEMBER_BINOP(mul_multi_mod)
246     FLINTXX_DEFINE_MEMBER_BINOP(pow)
247 
248     FLINTXX_DEFINE_MEMBER_BINOP(solve)
249     FLINTXX_DEFINE_MEMBER_BINOP(solve_bound)
250     FLINTXX_DEFINE_MEMBER_BINOP(solve_cramer)
251     FLINTXX_DEFINE_MEMBER_BINOP(solve_dixon)
252     FLINTXX_DEFINE_MEMBER_BINOP(solve_fflu)
253 
254     FLINTXX_DEFINE_MEMBER_3OP(det_modular_given_divisor)
255 
256     FLINTXX_DEFINE_MEMBER_UNOP(sqr)
257     FLINTXX_DEFINE_MEMBER_UNOP(transpose)
258 
259     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpz_polyxx, charpoly)
260     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, det)
261     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, det_bareiss)
262     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, det_bound)
263     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, det_cofactor)
264     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, det_divisor)
265     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, trace)
266     //FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(nullspace) // TODO
267     //FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(???, inv) // TODO
268     //FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(???, rref) // TODO
269 
270     FLINTXX_DEFINE_MEMBER_4OP(CRT)
271 
272     FLINTXX_DEFINE_MEMBER_FFLU
273 };
274 
275 namespace detail {
276 struct fmpz_mat_data;
277 } // detail
278 
279 typedef fmpz_matxx_expression<operations::immediate, detail::fmpz_mat_data> fmpz_matxx;
280 typedef fmpz_matxx_expression<operations::immediate,
281             flint_classes::ref_data<fmpz_matxx, fmpz_mat_struct> > fmpz_matxx_ref;
282 typedef fmpz_matxx_expression<operations::immediate, flint_classes::srcref_data<
283     fmpz_matxx, fmpz_matxx_ref, fmpz_mat_struct> > fmpz_matxx_srcref;
284 
285 template<>
286 struct matrix_traits<fmpz_matxx>
287 {
288     template<class M> static slong rows(const M& m)
289     {
290         return fmpz_mat_nrows(m._mat());
291     }
292     template<class M> static slong cols(const M& m)
293     {
294         return fmpz_mat_ncols(m._mat());
295     }
296 
297     template<class M> static fmpzxx_srcref at(const M& m, slong i, slong j)
298     {
299         return fmpzxx_srcref::make(fmpz_mat_entry(m._mat(), i, j));
300     }
301     template<class M> static fmpzxx_ref at(M& m, slong i, slong j)
302     {
303         return fmpzxx_ref::make(fmpz_mat_entry(m._mat(), i, j));
304     }
305 };
306 
307 namespace detail {
308 template<>
309 struct fmpz_matxx_traits<fmpz_matxx_srcref>
310     : matrices::generic_traits_srcref<fmpzxx_srcref> { };
311 template<>
312 struct fmpz_matxx_traits<fmpz_matxx_ref>
313     : matrices::generic_traits_ref<fmpzxx_ref> { };
314 template<> struct fmpz_matxx_traits<fmpz_matxx>
315     : matrices::generic_traits_nonref<fmpzxx_ref, fmpzxx_srcref> { };
316 
317 struct fmpz_mat_data
318 {
319     typedef fmpz_mat_t& data_ref_t;
320     typedef const fmpz_mat_t& data_srcref_t;
321 
322     fmpz_mat_t inner;
323 
324     fmpz_mat_data(slong m, slong n)
325     {
326         fmpz_mat_init(inner, m, n);
327     }
328 
329     fmpz_mat_data(const fmpz_mat_data& o)
330     {
331         fmpz_mat_init_set(inner, o.inner);
332     }
333 
334     fmpz_mat_data(fmpz_matxx_srcref o)
335     {
336         fmpz_mat_init_set(inner, o._data().inner);
337     }
338 
339     ~fmpz_mat_data() {fmpz_mat_clear(inner);}
340 };
341 } // detail
342 
343 #define FMPZ_MATXX_COND_S FLINTXX_COND_S(fmpz_matxx)
344 #define FMPZ_MATXX_COND_T FLINTXX_COND_T(fmpz_matxx)
345 
346 namespace traits {
347 template<class T> struct is_fmpz_matxx
348     : flint_classes::is_Base<fmpz_matxx, T> { };
349 } // traits
350 namespace mp {
351 template<class T1, class T2 = void, class T3 = void, class T4 = void>
352 struct all_fmpz_matxx : mp::and_<all_fmpz_matxx<T1>, all_fmpz_matxx<T2, T3, T4> > { };
353 template<class T>
354 struct all_fmpz_matxx<T, void, void, void> : traits::is_fmpz_matxx<T> { };
355 
356 template<class Out, class T1, class T2 = void, class T3 = void, class T4 = void>
357 struct enable_all_fmpz_matxx
358     : mp::enable_if<all_fmpz_matxx<T1, T2, T3, T4>, Out> { };
359 } // mp
360 
361 namespace matrices {
362 template<>
363 struct outsize<operations::mul_multi_mod_op>
364     : outsize<operations::times> { };
365 
366 template<> struct outsize<operations::solve_cramer_op>
367     : outsize<operations::solve_op> { };
368 template<> struct outsize<operations::solve_dixon_op>
369     : outsize<operations::solve_op> { };
370 } // matrices
371 
372 // temporary instantiation stuff
373 FLINTXX_DEFINE_TEMPORARY_RULES(fmpz_matxx)
374 
375 namespace rules {
376 FLINT_DEFINE_DOIT_COND2(assignment, FMPZ_MATXX_COND_T, FMPZ_MATXX_COND_S,
377         fmpz_mat_set(to._mat(), from._mat()))
378 
379 FLINTXX_DEFINE_SWAP(fmpz_matxx, fmpz_mat_swap(e1._mat(), e2._mat()))
380 
381 FLINTXX_DEFINE_EQUALS(fmpz_matxx, fmpz_mat_equal(e1._mat(), e2._mat()))
382 
383 FLINT_DEFINE_PRINT_COND(FMPZ_MATXX_COND_S, fmpz_mat_fprint(to, from._mat()))
384 FLINT_DEFINE_READ_COND(FMPZ_MATXX_COND_T, fmpz_mat_fread(from, to._mat()))
385 FLINT_DEFINE_PRINT_PRETTY_COND(FMPZ_MATXX_COND_S,
386         fmpz_mat_fprint_pretty(to, from._mat()))
387 
388 FLINT_DEFINE_BINARY_EXPR_COND2(times, fmpz_matxx,
389         FMPZ_MATXX_COND_S, FMPZ_MATXX_COND_S,
390         fmpz_mat_mul(to._mat(), e1._mat(), e2._mat()))
391 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpz_matxx,
392         FMPZ_MATXX_COND_S, FMPZXX_COND_S,
393         fmpz_mat_scalar_mul_fmpz(to._mat(), e1._mat(), e2._fmpz()))
394 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpz_matxx,
395         FMPZ_MATXX_COND_S, traits::is_unsigned_integer,
396         fmpz_mat_scalar_mul_ui(to._mat(), e1._mat(), e2))
397 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpz_matxx,
398         FMPZ_MATXX_COND_S, traits::is_signed_integer,
399         fmpz_mat_scalar_mul_si(to._mat(), e1._mat(), e2))
400 
401 FLINT_DEFINE_BINARY_EXPR_COND2(divexact_op, fmpz_matxx,
402         FMPZ_MATXX_COND_S, FMPZXX_COND_S,
403         fmpz_mat_scalar_divexact_fmpz(to._mat(), e1._mat(), e2._fmpz()))
404 FLINT_DEFINE_BINARY_EXPR_COND2(divexact_op, fmpz_matxx,
405         FMPZ_MATXX_COND_S, traits::is_unsigned_integer,
406         fmpz_mat_scalar_divexact_ui(to._mat(), e1._mat(), e2))
407 FLINT_DEFINE_BINARY_EXPR_COND2(divexact_op, fmpz_matxx,
408         FMPZ_MATXX_COND_S, traits::is_signed_integer,
409         fmpz_mat_scalar_divexact_si(to._mat(), e1._mat(), e2))
410 
411 FLINT_DEFINE_BINARY_EXPR_COND2(plus, fmpz_matxx,
412         FMPZ_MATXX_COND_S, FMPZ_MATXX_COND_S,
413         fmpz_mat_add(to._mat(), e1._mat(), e2._mat()))
414 FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpz_matxx,
415         FMPZ_MATXX_COND_S, FMPZ_MATXX_COND_S,
416         fmpz_mat_sub(to._mat(), e1._mat(), e2._mat()))
417 
418 FLINT_DEFINE_UNARY_EXPR_COND(negate, fmpz_matxx, FMPZ_MATXX_COND_S,
419         fmpz_mat_neg(to._mat(), from._mat()))
420 
421 FLINT_DEFINE_UNARY_EXPR_COND(transpose_op, fmpz_matxx, FMPZ_MATXX_COND_S,
422         fmpz_mat_transpose(to._mat(), from._mat()))
423 FLINT_DEFINE_UNARY_EXPR_COND(trace_op, fmpzxx, FMPZ_MATXX_COND_S,
424         fmpz_mat_trace(to._fmpz(), from._mat()))
425 
426 #define FMPZ_MATXX_DEFINE_DET(name) \
427 FLINT_DEFINE_UNARY_EXPR_COND(name##_op, fmpzxx, FMPZ_MATXX_COND_S, \
428         fmpz_mat_##name(to._fmpz(), from._mat()))
429 FMPZ_MATXX_DEFINE_DET(det)
430 FMPZ_MATXX_DEFINE_DET(det_cofactor)
431 FMPZ_MATXX_DEFINE_DET(det_bareiss)
432 FMPZ_MATXX_DEFINE_DET(det_divisor)
433 FMPZ_MATXX_DEFINE_DET(det_bound)
434 
435 FLINT_DEFINE_BINARY_EXPR_COND2(det_modular_op, fmpzxx,
436         FMPZ_MATXX_COND_S, tools::is_bool,
437         fmpz_mat_det_modular(to._fmpz(), e1._mat(), e2))
438 FLINT_DEFINE_BINARY_EXPR_COND2(det_modular_accelerated_op, fmpzxx,
439         FMPZ_MATXX_COND_S, tools::is_bool,
440         fmpz_mat_det_modular_accelerated(to._fmpz(), e1._mat(), e2))
441 FLINT_DEFINE_THREEARY_EXPR_COND3(det_modular_given_divisor_op, fmpzxx,
442         FMPZ_MATXX_COND_S, FMPZXX_COND_S, tools::is_bool,
443         fmpz_mat_det_modular_given_divisor(to._fmpz(), e1._mat(), e2._fmpz(), e3))
444 
445 FLINT_DEFINE_THREEARY_EXPR_COND3(mat_at_op, fmpzxx,
446         FMPZ_MATXX_COND_S, traits::fits_into_slong, traits::fits_into_slong,
447         fmpz_set(to._fmpz(), fmpz_mat_entry(e1._mat(), e2, e3)))
448 
449 FLINT_DEFINE_BINARY_EXPR_COND2(mul_classical_op, fmpz_matxx,
450         FMPZ_MATXX_COND_S, FMPZ_MATXX_COND_S,
451         fmpz_mat_mul_classical(to._mat(), e1._mat(), e2._mat()))
452 FLINT_DEFINE_BINARY_EXPR_COND2(mul_multi_mod_op, fmpz_matxx,
453         FMPZ_MATXX_COND_S, FMPZ_MATXX_COND_S,
454         fmpz_mat_mul_multi_mod(to._mat(), e1._mat(), e2._mat()))
455 
456 FLINT_DEFINE_UNARY_EXPR_COND(sqr_op, fmpz_matxx, FMPZ_MATXX_COND_S,
457         fmpz_mat_sqr(to._mat(), from._mat()))
458 FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, fmpz_matxx,
459         FMPZ_MATXX_COND_S, traits::is_unsigned_integer,
460         fmpz_mat_pow(to._mat(), e1._mat(), e2))
461 
462 namespace rdetail {
463 typedef make_ltuple<mp::make_tuple<bool, fmpz_matxx, fmpzxx>::type >::type
464     fmpz_mat_inv_rt;
465 
466 typedef make_ltuple<mp::make_tuple<fmpzxx, fmpzxx>::type >::type
467     fmpz_solve_bound_rt;
468 
469 typedef make_ltuple<mp::make_tuple<slong, fmpz_matxx>::type >::type
470     fmpz_mat_nullspace_rt;
471 } // rdetail
472 
473 FLINT_DEFINE_UNARY_EXPR_COND(inv_op, rdetail::fmpz_mat_inv_rt,
474         FMPZ_MATXX_COND_S,
475         to.template get<0>() = fmpz_mat_inv(to.template get<1>()._mat(),
476             to.template get<2>()._fmpz(), from._mat()))
477 
478 FLINT_DEFINE_UNARY_EXPR_COND(charpoly_op, fmpz_polyxx, FMPZ_MATXX_COND_S,
479         fmpz_mat_charpoly(to._poly(), from._mat()))
480 
481 #define FMPZ_MATXX_DEFINE_SOLVE(name) \
482 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, rdetail::fmpz_mat_inv_rt, \
483         FMPZ_MATXX_COND_S, FMPZ_MATXX_COND_S, \
484         to.template get<0>() = fmpz_mat_##name(to.template get<1>()._mat(), \
485             to.template get<2>()._fmpz(), e1._mat(), e2._mat()))
486 FMPZ_MATXX_DEFINE_SOLVE(solve)
487 FMPZ_MATXX_DEFINE_SOLVE(solve_dixon)
488 FMPZ_MATXX_DEFINE_SOLVE(solve_cramer)
489 FMPZ_MATXX_DEFINE_SOLVE(solve_fflu)
490 
491 FLINT_DEFINE_BINARY_EXPR_COND2(solve_bound_op,
492         rdetail::fmpz_solve_bound_rt,
493         FMPZ_MATXX_COND_S, FMPZ_MATXX_COND_S,
494         fmpz_mat_solve_bound(to.template get<0>()._fmpz(),
495             to.template get<1>()._fmpz(), e1._mat(), e2._mat()))
496 
497 FLINT_DEFINE_UNARY_EXPR_COND(nullspace_op, rdetail::fmpz_mat_nullspace_rt,
498         FMPZ_MATXX_COND_S, to.template get<0>() = fmpz_mat_nullspace(
499             to.template get<1>()._mat(), from._mat()))
500 
501 namespace rdetail {
502 typedef make_ltuple<mp::make_tuple<slong, fmpz_matxx, fmpzxx>::type>::type
503     fmpz_matxx_fflu_rt;
504 } // rdetail
505 
506 FLINT_DEFINE_THREEARY_EXPR_COND3(fflu_op, rdetail::fmpz_matxx_fflu_rt,
507         FMPZ_MATXX_COND_S, traits::is_maybe_perm, tools::is_bool,
508         to.template get<0>() = fmpz_mat_fflu(to.template get<1>()._mat(),
509             to.template get<2>()._fmpz(), maybe_perm_data(e2), e1._mat(), e3))
510 
511 FLINT_DEFINE_UNARY_EXPR_COND(rref_op, rdetail::fmpz_matxx_fflu_rt,
512         FMPZ_MATXX_COND_S,
513         to.template get<0>() = fmpz_mat_rref(to.template get<1>()._mat(),
514             to.template get<2>()._fmpz(), from._mat()))
515 } // rules
516 } // flint
517 
518 #include "nmod_matxx.h" // modular reconstruction code
519 
520 #endif
521