Make fmpz_mat
preserve the domain in .inv()
and .rref()
.
#198
Labels
fmpz_mat
preserve the domain in .inv()
and .rref()
.
#198
This follows on from gh-109 which makes division (
a / b
) exact and gh-72 which ensures that poly roots methods return roots in the ground domain. As far as I know there are now only two places in python-flint where the domain is implicitly changed during an operation which arefmpz_mat.inv()
andfmpz_mat.solve()
:Another inconsistency is found with
fmpz_mat.rref()
where most types have an.rref()
method that returns a 2-tuple(RREF, rank)
thefmpz_mat.rref()
method returns a 3-tuple(RREF, denominator, rank)
from fraction-free RREF. This preserves the domain but not the interface of the.rref()
method:Currently
fmpz_mat
is the only matrix type where the ground domain is an integral-domain but not a field (all other types are fields except nmod/fmpz_mod with non-prime modulus). That means that right nowfmpz_mat
is the only type for which it makes sense to have fraction-free methods but ideally in future there will be more e.g. matrices with polynomial entries,gr_mat
etc.We need a better system that ensures that all types can have consistent interfaces and preserve the domain. The way I handled this with SymPy's
DomainMatrix
is very similar to the way it is handled in Flint'sgr_mat
generic type and uses the exact same naming convention (I don't think I had seen thegr_mat
function names at the time...):inv
vsinv_den
rref
vsrref_den
solve
vssolve_den
Here the first set like
inv
,rref
etc are defined for fields and the second set are defined for all integral domains. Both sets always preserve the domain.We should add methods
inv_den
,rref_den
, etc to all matrix types (they could still raise for non-prime modulus). The currentfmpz_mat.rref()
method should just be renamed torref_den()
.Then
fmpz_mat.rref()
should be a function that either returns a 2-tuple (fmpz_mat
, rank) or raises an error. The implementation is just:Given python-flint's use of exact division I think that what makes most sense is that
fmpz_mat.inv()
should return anfmpz_mat
if possible and raise an error otherwise (if the matrix is not unimodular). Again the implementation is simple:The
gr_mat
functions for some of these operations are:gr_mat_inv
gr_mat_nonsingular_solve
gr_mat_nonsingular_solve_den
gr_mat_rref
gr_mat_rref_den
If I understand the docs correctly these all do exactly what I described above for the corresponding method names. There is no
gr_mat_inv_den
but the docs suggest usinggr_mat_nonsingular_solve_den
and I think it would be worth having a method calledinv_den
in python-flint since the implementation is trivial:I'm not sure about the name
nonsingular_solve
vssolve
. The convention in python-flint is alreadysolve
forfmpz_mat
,fmpq_mat
,arb_mat
andacb_mat
. This is like the Flint functionsfmpz_mat_solve
andfmpq_mat_solve
etc whose meaning corresponds either tosolve
orsolve_den
as described above. Thegr_mat
methods are all callednonsingular_solve
ornonsingular_solve_den
with the exception ofgr_solve_field
which does not require an invertible matrix.The other method names relevant here but not used yet in python-flint are
lu
andfflu
which is analogous to e.g.rref
vsrref_den
. I think the same convention could be used in python-flint for LU decompositions.What this all means for now is that we need to change
fmpz_mat.inv
,fmpz_mat.solve
andfmpz_mat.rref
in an incompatible way for consistency with current and future matrix types. All three methods need to be changed to returnfmpz_mat
always and to raise an error if the result cannot be represented as anfmpz_mat
.I don't think anything special needs to be done to ease the impact of compatibility breakage because the old behaviour is available trivially by converting to
fmpq_mat
e.g.or by just calling the new method name:
If someone needs to straddle both new and old versions of python-flint then converting to
fmpq_mat
already works in older versions. In the RREF case the can do something like:The text was updated successfully, but these errors were encountered: